Home | History | Annotate | Download | only in renderer_host
      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