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