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. 4 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/gpu_data_manager_impl.h" 10 #include "content/browser/renderer_host/dip_util.h" 11 #include "content/browser/renderer_host/render_widget_host_impl.h" 12 #include "content/port/browser/render_widget_host_view_frame_subscriber.h" 13 #include "content/port/browser/render_widget_host_view_port.h" 14 #include "content/public/browser/compositor_util.h" 15 #include "content/public/browser/render_view_host.h" 16 #include "content/public/browser/web_contents.h" 17 #include "content/public/common/content_paths.h" 18 #include "content/public/common/content_switches.h" 19 #include "content/public/common/url_constants.h" 20 #include "content/public/test/browser_test_utils.h" 21 #include "content/shell/shell.h" 22 #include "content/test/content_browser_test.h" 23 #include "content/test/content_browser_test_utils.h" 24 #include "media/base/video_frame.h" 25 #include "media/filters/skcanvas_video_renderer.h" 26 #include "net/base/net_util.h" 27 #include "third_party/skia/include/core/SkBitmap.h" 28 #include "third_party/skia/include/core/SkCanvas.h" 29 #include "third_party/skia/include/core/SkDevice.h" 30 #include "ui/base/ui_base_switches.h" 31 #include "ui/gfx/size_conversions.h" 32 #include "ui/gl/gl_switches.h" 33 34 #if defined(OS_MACOSX) 35 #include "ui/gl/io_surface_support_mac.h" 36 #endif 37 38 #if defined(OS_WIN) 39 #include "ui/base/win/dpi.h" 40 #endif 41 42 namespace content { 43 namespace { 44 45 // Convenience macro: Short-circuit a pass for the tests where platform support 46 // for forced-compositing mode (or disabled-compositing mode) is lacking. 47 #define SET_UP_SURFACE_OR_PASS_TEST(wait_message) \ 48 if (!SetUpSourceSurface(wait_message)) { \ 49 LOG(WARNING) \ 50 << ("Blindly passing this test: This platform does not support " \ 51 "forced compositing (or forced-disabled compositing) mode."); \ 52 return; \ 53 } 54 55 // Convenience macro: Short-circuit a pass for platforms where setting up 56 // high-DPI fails. 57 #define PASS_TEST_IF_SCALE_FACTOR_NOT_SUPPORTED(factor) \ 58 if (ui::GetScaleFactorScale( \ 59 GetScaleFactorForView(GetRenderWidgetHostViewPort())) != factor) { \ 60 LOG(WARNING) << "Blindly passing this test: failed to set up " \ 61 "scale factor: " << factor; \ 62 return false; \ 63 } 64 65 // Common base class for browser tests. This is subclassed twice: Once to test 66 // the browser in forced-compositing mode, and once to test with compositing 67 // mode disabled. 68 class RenderWidgetHostViewBrowserTest : public ContentBrowserTest { 69 public: 70 RenderWidgetHostViewBrowserTest() 71 : frame_size_(400, 300), 72 callback_invoke_count_(0), 73 frames_captured_(0) {} 74 75 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 76 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir_)); 77 ContentBrowserTest::SetUpInProcessBrowserTestFixture(); 78 } 79 80 // Attempts to set up the source surface. Returns false if unsupported on the 81 // current platform. 82 virtual bool SetUpSourceSurface(const char* wait_message) = 0; 83 84 int callback_invoke_count() const { 85 return callback_invoke_count_; 86 } 87 88 int frames_captured() const { 89 return frames_captured_; 90 } 91 92 const gfx::Size& frame_size() const { 93 return frame_size_; 94 } 95 96 const base::FilePath& test_dir() const { 97 return test_dir_; 98 } 99 100 RenderViewHost* GetRenderViewHost() const { 101 RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost(); 102 CHECK(rvh); 103 return rvh; 104 } 105 106 RenderWidgetHostImpl* GetRenderWidgetHost() const { 107 RenderWidgetHostImpl* const rwh = RenderWidgetHostImpl::From( 108 shell()->web_contents()->GetRenderWidgetHostView()-> 109 GetRenderWidgetHost()); 110 CHECK(rwh); 111 return rwh; 112 } 113 114 RenderWidgetHostViewPort* GetRenderWidgetHostViewPort() const { 115 RenderWidgetHostViewPort* const view = 116 RenderWidgetHostViewPort::FromRWHV(GetRenderViewHost()->GetView()); 117 CHECK(view); 118 return view; 119 } 120 121 // Callback when using CopyFromBackingStore() API. 122 void FinishCopyFromBackingStore(const base::Closure& quit_closure, 123 bool frame_captured, 124 const SkBitmap& bitmap) { 125 ++callback_invoke_count_; 126 if (frame_captured) { 127 ++frames_captured_; 128 EXPECT_FALSE(bitmap.empty()); 129 } 130 if (!quit_closure.is_null()) 131 quit_closure.Run(); 132 } 133 134 // Callback when using CopyFromCompositingSurfaceToVideoFrame() API. 135 void FinishCopyFromCompositingSurface(const base::Closure& quit_closure, 136 bool frame_captured) { 137 ++callback_invoke_count_; 138 if (frame_captured) 139 ++frames_captured_; 140 if (!quit_closure.is_null()) 141 quit_closure.Run(); 142 } 143 144 // Callback when using frame subscriber API. 145 void FrameDelivered(const scoped_refptr<base::MessageLoopProxy>& loop, 146 base::Closure quit_closure, 147 base::Time timestamp, 148 bool frame_captured) { 149 ++callback_invoke_count_; 150 if (frame_captured) 151 ++frames_captured_; 152 if (!quit_closure.is_null()) 153 loop->PostTask(FROM_HERE, quit_closure); 154 } 155 156 // Copy one frame using the CopyFromBackingStore API. 157 void RunBasicCopyFromBackingStoreTest() { 158 SET_UP_SURFACE_OR_PASS_TEST(NULL); 159 160 // Repeatedly call CopyFromBackingStore() since, on some platforms (e.g., 161 // Windows), the operation will fail until the first "present" has been 162 // made. 163 int count_attempts = 0; 164 while (true) { 165 ++count_attempts; 166 base::RunLoop run_loop; 167 GetRenderViewHost()->CopyFromBackingStore( 168 gfx::Rect(), 169 frame_size(), 170 base::Bind( 171 &RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore, 172 base::Unretained(this), 173 run_loop.QuitClosure())); 174 run_loop.Run(); 175 176 if (frames_captured()) 177 break; 178 else 179 GiveItSomeTime(); 180 } 181 182 EXPECT_EQ(count_attempts, callback_invoke_count()); 183 EXPECT_EQ(1, frames_captured()); 184 } 185 186 protected: 187 // Waits until the source is available for copying. 188 void WaitForCopySourceReady() { 189 while (!GetRenderWidgetHostViewPort()->IsSurfaceAvailableForCopy()) 190 GiveItSomeTime(); 191 } 192 193 // Run the current message loop for a short time without unwinding the current 194 // call stack. 195 static void GiveItSomeTime() { 196 base::RunLoop run_loop; 197 base::MessageLoop::current()->PostDelayedTask( 198 FROM_HERE, 199 run_loop.QuitClosure(), 200 base::TimeDelta::FromMilliseconds(10)); 201 run_loop.Run(); 202 } 203 204 private: 205 const gfx::Size frame_size_; 206 base::FilePath test_dir_; 207 int callback_invoke_count_; 208 int frames_captured_; 209 }; 210 211 class CompositingRenderWidgetHostViewBrowserTest 212 : public RenderWidgetHostViewBrowserTest { 213 public: 214 virtual void SetUp() OVERRIDE { 215 // We expect real pixel output for these tests. 216 UseRealGLContexts(); 217 218 // On legacy windows, these tests need real GL bindings to pass. 219 #if defined(OS_WIN) && !defined(USE_AURA) 220 UseRealGLBindings(); 221 #endif 222 223 RenderWidgetHostViewBrowserTest::SetUp(); 224 } 225 226 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 227 // Note: Not appending kForceCompositingMode switch here, since not all bots 228 // support compositing. Some bots will run with compositing on, and others 229 // won't. Therefore, the call to SetUpSourceSurface() later on will detect 230 // whether compositing mode is actually on or not. If not, the tests will 231 // pass blindly, logging a warning message, since we cannot test what the 232 // platform/implementation does not support. 233 RenderWidgetHostViewBrowserTest::SetUpCommandLine(command_line); 234 } 235 236 virtual GURL TestUrl() { 237 return net::FilePathToFileURL( 238 test_dir().AppendASCII("rwhv_compositing_animation.html")); 239 } 240 241 virtual bool SetUpSourceSurface(const char* wait_message) OVERRIDE { 242 if (!IsForceCompositingModeEnabled()) 243 return false; // See comment in SetUpCommandLine(). 244 #if defined(OS_MACOSX) 245 CHECK(IOSurfaceSupport::Initialize()); 246 #endif 247 248 content::DOMMessageQueue message_queue; 249 NavigateToURL(shell(), TestUrl()); 250 if (wait_message != NULL) { 251 std::string result(wait_message); 252 if (!message_queue.WaitForMessage(&result)) { 253 EXPECT_TRUE(false) << "WaitForMessage " << result << " failed."; 254 return false; 255 } 256 } 257 258 #if !defined(USE_AURA) 259 if (!GetRenderWidgetHost()->is_accelerated_compositing_active()) 260 return false; // Renderer did not turn on accelerated compositing. 261 #endif 262 263 // Using accelerated compositing, but a compositing surface might not be 264 // available yet. So, wait for it. 265 WaitForCopySourceReady(); 266 return true; 267 } 268 }; 269 270 class NonCompositingRenderWidgetHostViewBrowserTest 271 : public RenderWidgetHostViewBrowserTest { 272 public: 273 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 274 // Note: Appending the kDisableAcceleratedCompositing switch here, but there 275 // are some builds that only use compositing and will ignore this switch. 276 // Therefore, the call to SetUpSourceSurface() later on will detect whether 277 // compositing mode is actually off. If it's on, the tests will pass 278 // blindly, logging a warning message, since we cannot test what the 279 // platform/implementation does not support. 280 command_line->AppendSwitch(switches::kDisableAcceleratedCompositing); 281 RenderWidgetHostViewBrowserTest::SetUpCommandLine(command_line); 282 } 283 284 virtual GURL TestUrl() { 285 return GURL(kAboutBlankURL); 286 } 287 288 virtual bool SetUpSourceSurface(const char* wait_message) OVERRIDE { 289 if (IsForceCompositingModeEnabled()) 290 return false; // See comment in SetUpCommandLine(). 291 292 content::DOMMessageQueue message_queue; 293 NavigateToURL(shell(), TestUrl()); 294 if (wait_message != NULL) { 295 std::string result(wait_message); 296 if (!message_queue.WaitForMessage(&result)) { 297 EXPECT_TRUE(false) << "WaitForMessage " << result << " failed."; 298 return false; 299 } 300 } 301 302 WaitForCopySourceReady(); 303 // Return whether the renderer left accelerated compositing turned off. 304 return !GetRenderWidgetHost()->is_accelerated_compositing_active(); 305 } 306 }; 307 308 class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 309 public: 310 FakeFrameSubscriber( 311 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback) 312 : callback_(callback) { 313 } 314 315 virtual bool ShouldCaptureFrame( 316 base::Time present_time, 317 scoped_refptr<media::VideoFrame>* storage, 318 DeliverFrameCallback* callback) OVERRIDE { 319 // Only allow one frame capture to be made. Otherwise, the compositor could 320 // start multiple captures, unbounded, and eventually its own limiter logic 321 // will begin invoking |callback| with a |false| result. This flakes out 322 // the unit tests, since they receive a "failed" callback before the later 323 // "success" callbacks. 324 if (callback_.is_null()) 325 return false; 326 *storage = media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100)); 327 *callback = callback_; 328 callback_.Reset(); 329 return true; 330 } 331 332 private: 333 DeliverFrameCallback callback_; 334 }; 335 336 // Disable tests for Android and IOS as these platforms have incomplete 337 // implementation. 338 #if !defined(OS_ANDROID) && !defined(OS_IOS) 339 340 // The CopyFromBackingStore() API should work on all platforms when compositing 341 // is enabled. 342 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTest, 343 CopyFromBackingStore) { 344 RunBasicCopyFromBackingStoreTest(); 345 } 346 347 // The CopyFromBackingStore() API should work on all platforms when compositing 348 // is disabled. 349 IN_PROC_BROWSER_TEST_F(NonCompositingRenderWidgetHostViewBrowserTest, 350 CopyFromBackingStore) { 351 RunBasicCopyFromBackingStoreTest(); 352 } 353 354 // Tests that the callback passed to CopyFromBackingStore is always called, 355 // even when the RenderWidgetHost is deleting in the middle of an async copy. 356 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTest, 357 CopyFromBackingStore_CallbackDespiteDelete) { 358 SET_UP_SURFACE_OR_PASS_TEST(NULL); 359 360 base::RunLoop run_loop; 361 GetRenderViewHost()->CopyFromBackingStore( 362 gfx::Rect(), 363 frame_size(), 364 base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore, 365 base::Unretained(this), run_loop.QuitClosure())); 366 // Delete the surface before the callback is run. 367 GetRenderWidgetHostViewPort()->AcceleratedSurfaceRelease(); 368 run_loop.Run(); 369 370 EXPECT_EQ(1, callback_invoke_count()); 371 } 372 373 // Tests that the callback passed to CopyFromCompositingSurfaceToVideoFrame is 374 // always called, even when the RenderWidgetHost is deleting in the middle of 375 // an async copy. 376 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTest, 377 CopyFromCompositingSurface_CallbackDespiteDelete) { 378 SET_UP_SURFACE_OR_PASS_TEST(NULL); 379 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort(); 380 if (!view->CanCopyToVideoFrame()) { 381 LOG(WARNING) << 382 ("Blindly passing this test: CopyFromCompositingSurfaceToVideoFrame() " 383 "not supported on this platform."); 384 return; 385 } 386 387 base::RunLoop run_loop; 388 scoped_refptr<media::VideoFrame> dest = 389 media::VideoFrame::CreateBlackFrame(frame_size()); 390 view->CopyFromCompositingSurfaceToVideoFrame( 391 gfx::Rect(view->GetViewBounds().size()), dest, base::Bind( 392 &RenderWidgetHostViewBrowserTest::FinishCopyFromCompositingSurface, 393 base::Unretained(this), run_loop.QuitClosure())); 394 // Delete the surface before the callback is run. 395 view->AcceleratedSurfaceRelease(); 396 run_loop.Run(); 397 398 EXPECT_EQ(1, callback_invoke_count()); 399 } 400 401 // With compositing turned off, no platforms should support the 402 // CopyFromCompositingSurfaceToVideoFrame() API. 403 IN_PROC_BROWSER_TEST_F(NonCompositingRenderWidgetHostViewBrowserTest, 404 CopyFromCompositingSurfaceToVideoFrameCallbackTest) { 405 SET_UP_SURFACE_OR_PASS_TEST(NULL); 406 EXPECT_FALSE(GetRenderWidgetHostViewPort()->CanCopyToVideoFrame()); 407 } 408 409 // Test basic frame subscription functionality. We subscribe, and then run 410 // until at least one DeliverFrameCallback has been invoked. 411 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTest, 412 FrameSubscriberTest) { 413 SET_UP_SURFACE_OR_PASS_TEST(NULL); 414 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort(); 415 if (!view->CanSubscribeFrame()) { 416 LOG(WARNING) << ("Blindly passing this test: Frame subscription not " 417 "supported on this platform."); 418 return; 419 } 420 421 base::RunLoop run_loop; 422 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( 423 new FakeFrameSubscriber( 424 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered, 425 base::Unretained(this), 426 base::MessageLoopProxy::current(), 427 run_loop.QuitClosure()))); 428 view->BeginFrameSubscription(subscriber.Pass()); 429 run_loop.Run(); 430 view->EndFrameSubscription(); 431 432 EXPECT_LE(1, callback_invoke_count()); 433 EXPECT_LE(1, frames_captured()); 434 } 435 436 // Test that we can copy twice from an accelerated composited page. 437 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTest, CopyTwice) { 438 SET_UP_SURFACE_OR_PASS_TEST(NULL); 439 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort(); 440 if (!view->CanCopyToVideoFrame()) { 441 LOG(WARNING) << ("Blindly passing this test: " 442 "CopyFromCompositingSurfaceToVideoFrame() not supported " 443 "on this platform."); 444 return; 445 } 446 447 base::RunLoop run_loop; 448 scoped_refptr<media::VideoFrame> first_output = 449 media::VideoFrame::CreateBlackFrame(frame_size()); 450 ASSERT_TRUE(first_output.get()); 451 scoped_refptr<media::VideoFrame> second_output = 452 media::VideoFrame::CreateBlackFrame(frame_size()); 453 ASSERT_TRUE(second_output.get()); 454 view->CopyFromCompositingSurfaceToVideoFrame( 455 gfx::Rect(view->GetViewBounds().size()), 456 first_output, 457 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered, 458 base::Unretained(this), 459 base::MessageLoopProxy::current(), 460 base::Closure(), 461 base::Time::Now())); 462 view->CopyFromCompositingSurfaceToVideoFrame( 463 gfx::Rect(view->GetViewBounds().size()), second_output, 464 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered, 465 base::Unretained(this), 466 base::MessageLoopProxy::current(), 467 run_loop.QuitClosure(), 468 base::Time::Now())); 469 run_loop.Run(); 470 471 EXPECT_EQ(2, callback_invoke_count()); 472 EXPECT_EQ(2, frames_captured()); 473 } 474 475 class CompositingRenderWidgetHostViewBrowserTestTabCapture 476 : public CompositingRenderWidgetHostViewBrowserTest { 477 public: 478 CompositingRenderWidgetHostViewBrowserTestTabCapture() 479 : expected_copy_from_compositing_surface_result_(false), 480 allowable_error_(0), 481 test_url_("data:text/html,<!doctype html>") {} 482 483 void CopyFromCompositingSurfaceCallback(base::Closure quit_callback, 484 bool result, 485 const SkBitmap& bitmap) { 486 EXPECT_EQ(expected_copy_from_compositing_surface_result_, result); 487 if (!result) { 488 quit_callback.Run(); 489 return; 490 } 491 492 const SkBitmap& expected_bitmap = 493 expected_copy_from_compositing_surface_bitmap_; 494 EXPECT_EQ(expected_bitmap.width(), bitmap.width()); 495 EXPECT_EQ(expected_bitmap.height(), bitmap.height()); 496 EXPECT_EQ(expected_bitmap.config(), bitmap.config()); 497 SkAutoLockPixels expected_bitmap_lock(expected_bitmap); 498 SkAutoLockPixels bitmap_lock(bitmap); 499 int fails = 0; 500 for (int i = 0; i < bitmap.width() && fails < 10; ++i) { 501 for (int j = 0; j < bitmap.height() && fails < 10; ++j) { 502 if (!exclude_rect_.IsEmpty() && exclude_rect_.Contains(i, j)) 503 continue; 504 505 SkColor expected_color = expected_bitmap.getColor(i, j); 506 SkColor color = bitmap.getColor(i, j); 507 int expected_alpha = SkColorGetA(expected_color); 508 int alpha = SkColorGetA(color); 509 int expected_red = SkColorGetR(expected_color); 510 int red = SkColorGetR(color); 511 int expected_green = SkColorGetG(expected_color); 512 int green = SkColorGetG(color); 513 int expected_blue = SkColorGetB(expected_color); 514 int blue = SkColorGetB(color); 515 EXPECT_NEAR(expected_alpha, alpha, allowable_error_) 516 << "expected_color: " << std::hex << expected_color 517 << " color: " << color 518 << " Failed at " << std::dec << i << ", " << j 519 << " Failure " << ++fails; 520 EXPECT_NEAR(expected_red, red, allowable_error_) 521 << "expected_color: " << std::hex << expected_color 522 << " color: " << color 523 << " Failed at " << std::dec << i << ", " << j 524 << " Failure " << ++fails; 525 EXPECT_NEAR(expected_green, green, allowable_error_) 526 << "expected_color: " << std::hex << expected_color 527 << " color: " << color 528 << " Failed at " << std::dec << i << ", " << j 529 << " Failure " << ++fails; 530 EXPECT_NEAR(expected_blue, blue, allowable_error_) 531 << "expected_color: " << std::hex << expected_color 532 << " color: " << color 533 << " Failed at " << std::dec << i << ", " << j 534 << " Failure " << ++fails; 535 } 536 } 537 EXPECT_LT(fails, 10); 538 539 quit_callback.Run(); 540 } 541 542 void CopyFromCompositingSurfaceCallbackForVideo( 543 scoped_refptr<media::VideoFrame> video_frame, 544 base::Closure quit_callback, 545 bool result) { 546 EXPECT_EQ(expected_copy_from_compositing_surface_result_, result); 547 if (!result) { 548 quit_callback.Run(); 549 return; 550 } 551 552 media::SkCanvasVideoRenderer video_renderer; 553 554 SkBitmap bitmap; 555 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 556 video_frame->visible_rect().width(), 557 video_frame->visible_rect().height()); 558 bitmap.allocPixels(); 559 bitmap.setIsOpaque(true); 560 561 SkDevice device(bitmap); 562 SkCanvas canvas(&device); 563 564 video_renderer.Paint(video_frame.get(), 565 &canvas, 566 video_frame->visible_rect(), 567 0xff); 568 569 CopyFromCompositingSurfaceCallback(quit_callback, 570 result, 571 bitmap); 572 } 573 574 void SetExpectedCopyFromCompositingSurfaceResult(bool result, 575 const SkBitmap& bitmap) { 576 expected_copy_from_compositing_surface_result_ = result; 577 expected_copy_from_compositing_surface_bitmap_ = bitmap; 578 } 579 580 void SetAllowableError(int amount) { allowable_error_ = amount; } 581 void SetExcludeRect(gfx::Rect exclude) { exclude_rect_ = exclude; } 582 583 virtual GURL TestUrl() OVERRIDE { 584 return GURL(test_url_); 585 } 586 587 void SetTestUrl(std::string url) { test_url_ = url; } 588 589 // Loads a page two boxes side-by-side, each half the width of 590 // |html_rect_size|, and with different background colors. The test then 591 // copies from |copy_rect| region of the page into a bitmap of size 592 // |output_size|, and compares that with a bitmap of size 593 // |expected_bitmap_size|. 594 // Note that |output_size| may not have the same size as |copy_rect| (e.g. 595 // when the output is scaled). Also note that |expected_bitmap_size| may not 596 // be the same as |output_size| (e.g. when the device scale factor is not 1). 597 void PerformTestWithLeftRightRects(const gfx::Size& html_rect_size, 598 const gfx::Rect& copy_rect, 599 const gfx::Size& output_size, 600 const gfx::Size& expected_bitmap_size, 601 bool video_frame) { 602 const gfx::Size box_size(html_rect_size.width() / 2, 603 html_rect_size.height()); 604 SetTestUrl(base::StringPrintf( 605 "data:text/html,<!doctype html>" 606 "<div class='left'>" 607 " <div class='right'></div>" 608 "</div>" 609 "<style>" 610 "body { padding: 0; margin: 0; }" 611 ".left { position: absolute;" 612 " background: #0ff;" 613 " width: %dpx;" 614 " height: %dpx;" 615 "}" 616 ".right { position: absolute;" 617 " left: %dpx;" 618 " background: #ff0;" 619 " width: %dpx;" 620 " height: %dpx;" 621 "}" 622 "</style>" 623 "<script>" 624 " domAutomationController.setAutomationId(0);" 625 " domAutomationController.send(\"DONE\");" 626 "</script>", 627 box_size.width(), 628 box_size.height(), 629 box_size.width(), 630 box_size.width(), 631 box_size.height())); 632 633 SET_UP_SURFACE_OR_PASS_TEST("\"DONE\""); 634 if (!ShouldContinueAfterTestURLLoad()) 635 return; 636 637 RenderWidgetHostViewPort* rwhvp = GetRenderWidgetHostViewPort(); 638 639 // The page is loaded in the renderer, wait for a new frame to arrive. 640 uint32 frame = rwhvp->RendererFrameNumber(); 641 GetRenderWidgetHost()->ScheduleComposite(); 642 while (rwhvp->RendererFrameNumber() == frame) 643 GiveItSomeTime(); 644 645 SkBitmap expected_bitmap; 646 SetupLeftRightBitmap(expected_bitmap_size, &expected_bitmap); 647 SetExpectedCopyFromCompositingSurfaceResult(true, expected_bitmap); 648 649 base::RunLoop run_loop; 650 if (video_frame) { 651 // Allow pixel differences as long as we have the right idea. 652 SetAllowableError(0x10); 653 // Exclude the middle two columns which are blended between the two sides. 654 SetExcludeRect( 655 gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height())); 656 657 scoped_refptr<media::VideoFrame> video_frame = 658 media::VideoFrame::CreateFrame(media::VideoFrame::YV12, 659 expected_bitmap_size, 660 gfx::Rect(expected_bitmap_size), 661 expected_bitmap_size, 662 base::TimeDelta()); 663 664 base::Callback<void(bool success)> callback = 665 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture:: 666 CopyFromCompositingSurfaceCallbackForVideo, 667 base::Unretained(this), 668 video_frame, 669 run_loop.QuitClosure()); 670 rwhvp->CopyFromCompositingSurfaceToVideoFrame(copy_rect, 671 video_frame, 672 callback); 673 } else { 674 base::Callback<void(bool, const SkBitmap&)> callback = 675 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture:: 676 CopyFromCompositingSurfaceCallback, 677 base::Unretained(this), 678 run_loop.QuitClosure()); 679 rwhvp->CopyFromCompositingSurface(copy_rect, output_size, callback); 680 } 681 run_loop.Run(); 682 } 683 684 // Sets up |bitmap| to have size |copy_size|. It floods the left half with 685 // #0ff and the right half with #ff0. 686 void SetupLeftRightBitmap(const gfx::Size& copy_size, SkBitmap* bitmap) { 687 bitmap->setConfig( 688 SkBitmap::kARGB_8888_Config, copy_size.width(), copy_size.height()); 689 bitmap->allocPixels(); 690 // Left half is #0ff. 691 bitmap->eraseARGB(255, 0, 255, 255); 692 // Right half is #ff0. 693 { 694 SkAutoLockPixels lock(*bitmap); 695 for (int i = 0; i < copy_size.width() / 2; ++i) { 696 for (int j = 0; j < copy_size.height(); ++j) { 697 *(bitmap->getAddr32(copy_size.width() / 2 + i, j)) = 698 SkColorSetARGB(255, 255, 255, 0); 699 } 700 } 701 } 702 } 703 704 protected: 705 virtual bool ShouldContinueAfterTestURLLoad() { 706 return true; 707 } 708 709 private: 710 bool expected_copy_from_compositing_surface_result_; 711 SkBitmap expected_copy_from_compositing_surface_bitmap_; 712 int allowable_error_; 713 gfx::Rect exclude_rect_; 714 std::string test_url_; 715 }; 716 717 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTestTabCapture, 718 CopyFromCompositingSurface_Origin_Unscaled) { 719 gfx::Rect copy_rect(400, 300); 720 gfx::Size output_size = copy_rect.size(); 721 gfx::Size expected_bitmap_size = output_size; 722 gfx::Size html_rect_size(400, 300); 723 bool video_frame = false; 724 PerformTestWithLeftRightRects(html_rect_size, 725 copy_rect, 726 output_size, 727 expected_bitmap_size, 728 video_frame); 729 } 730 731 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTestTabCapture, 732 CopyFromCompositingSurface_Origin_Scaled) { 733 gfx::Rect copy_rect(400, 300); 734 gfx::Size output_size(200, 100); 735 gfx::Size expected_bitmap_size = output_size; 736 gfx::Size html_rect_size(400, 300); 737 bool video_frame = false; 738 PerformTestWithLeftRightRects(html_rect_size, 739 copy_rect, 740 output_size, 741 expected_bitmap_size, 742 video_frame); 743 } 744 745 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTestTabCapture, 746 CopyFromCompositingSurface_Cropped_Unscaled) { 747 // Grab 60x60 pixels from the center of the tab contents. 748 gfx::Rect copy_rect(400, 300); 749 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30), 750 gfx::Size(60, 60)); 751 gfx::Size output_size = copy_rect.size(); 752 gfx::Size expected_bitmap_size = output_size; 753 gfx::Size html_rect_size(400, 300); 754 bool video_frame = false; 755 PerformTestWithLeftRightRects(html_rect_size, 756 copy_rect, 757 output_size, 758 expected_bitmap_size, 759 video_frame); 760 } 761 762 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTestTabCapture, 763 CopyFromCompositingSurface_Cropped_Scaled) { 764 // Grab 60x60 pixels from the center of the tab contents. 765 gfx::Rect copy_rect(400, 300); 766 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30), 767 gfx::Size(60, 60)); 768 gfx::Size output_size(20, 10); 769 gfx::Size expected_bitmap_size = output_size; 770 gfx::Size html_rect_size(400, 300); 771 bool video_frame = false; 772 PerformTestWithLeftRightRects(html_rect_size, 773 copy_rect, 774 output_size, 775 expected_bitmap_size, 776 video_frame); 777 } 778 779 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTestTabCapture, 780 CopyFromCompositingSurface_ForVideoFrame) { 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 gfx::Size output_size = copy_rect.size(); 786 gfx::Size expected_bitmap_size = output_size; 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 expected_bitmap_size, 793 video_frame); 794 } 795 796 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTestTabCapture, 797 CopyFromCompositingSurface_ForVideoFrame_Scaled) { 798 // Grab 90x60 pixels from the center of the tab contents. 799 gfx::Rect copy_rect(400, 300); 800 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30), 801 gfx::Size(90, 60)); 802 // Scale to 30 x 20 (preserve aspect ratio). 803 gfx::Size output_size(30, 20); 804 gfx::Size expected_bitmap_size = output_size; 805 gfx::Size html_rect_size(400, 300); 806 bool video_frame = true; 807 PerformTestWithLeftRightRects(html_rect_size, 808 copy_rect, 809 output_size, 810 expected_bitmap_size, 811 video_frame); 812 } 813 814 class CompositingRenderWidgetHostViewTabCaptureHighDPI 815 : public CompositingRenderWidgetHostViewBrowserTestTabCapture { 816 public: 817 CompositingRenderWidgetHostViewTabCaptureHighDPI() 818 : kScale(2.f) { 819 } 820 821 virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE { 822 CompositingRenderWidgetHostViewBrowserTestTabCapture::SetUpCommandLine(cmd); 823 cmd->AppendSwitchASCII(switches::kForceDeviceScaleFactor, 824 base::StringPrintf("%f", scale())); 825 #if defined(OS_WIN) 826 cmd->AppendSwitchASCII(switches::kHighDPISupport, "1"); 827 ui::EnableHighDPISupport(); 828 #endif 829 } 830 831 float scale() const { return kScale; } 832 833 private: 834 virtual bool ShouldContinueAfterTestURLLoad() OVERRIDE { 835 PASS_TEST_IF_SCALE_FACTOR_NOT_SUPPORTED(scale()); 836 return true; 837 } 838 839 const float kScale; 840 841 DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewTabCaptureHighDPI); 842 }; 843 844 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewTabCaptureHighDPI, 845 CopyFromCompositingSurface) { 846 gfx::Rect copy_rect(200, 150); 847 gfx::Size output_size = copy_rect.size(); 848 gfx::Size expected_bitmap_size = 849 gfx::ToFlooredSize(gfx::ScaleSize(output_size, scale(), scale())); 850 gfx::Size html_rect_size(200, 150); 851 bool video_frame = false; 852 PerformTestWithLeftRightRects(html_rect_size, 853 copy_rect, 854 output_size, 855 expected_bitmap_size, 856 video_frame); 857 } 858 859 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewTabCaptureHighDPI, 860 CopyFromCompositingSurfaceVideoFrame) { 861 gfx::Size html_rect_size(200, 150); 862 // Grab 90x60 pixels from the center of the tab contents. 863 gfx::Rect copy_rect = 864 gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30), 865 gfx::Size(90, 60)); 866 gfx::Size output_size = copy_rect.size(); 867 gfx::Size expected_bitmap_size = 868 gfx::ToFlooredSize(gfx::ScaleSize(output_size, scale(), scale())); 869 bool video_frame = true; 870 PerformTestWithLeftRightRects(html_rect_size, 871 copy_rect, 872 output_size, 873 expected_bitmap_size, 874 video_frame); 875 } 876 877 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) 878 879 } // namespace 880 } // namespace content 881