Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / render_widget_host_view_browsertest.cc
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.get(), &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 #if defined(OS_WIN)
793 #define MAYBE_CopyToBitmap_EntireRegion DISABLED_CopyToBitmap_EntireRegion
794 #define MAYBE_CopyToBitmap_CenterRegion DISABLED_CopyToBitmap_CenterRegion
795 #define MAYBE_CopyToBitmap_ScaledResult DISABLED_CopyToBitmap_ScaledResult
796 #define MAYBE_CopyToVideoFrame_EntireRegion \
797             DISABLED_CopyToVideoFrame_EntireRegion
798 #define MAYBE_CopyToVideoFrame_CenterRegion \
799             DISABLED_CopyToVideoFrame_CenterRegion
800 #define MAYBE_CopyToVideoFrame_ScaledResult \
801             DISABLED_CopyToVideoFrame_ScaledResult
802 #else
803 #define MAYBE_CopyToBitmap_EntireRegion CopyToBitmap_EntireRegion
804 #define MAYBE_CopyToBitmap_CenterRegion CopyToBitmap_CenterRegion
805 #define MAYBE_CopyToBitmap_ScaledResult CopyToBitmap_ScaledResult
806 #define MAYBE_CopyToVideoFrame_EntireRegion CopyToVideoFrame_EntireRegion
807 #define MAYBE_CopyToVideoFrame_CenterRegion CopyToVideoFrame_CenterRegion
808 #define MAYBE_CopyToVideoFrame_ScaledResult CopyToVideoFrame_ScaledResult
809 #endif
810
811 IN_PROC_BROWSER_TEST_P(
812     CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
813     MAYBE_CopyToBitmap_EntireRegion) {
814   gfx::Size html_rect_size(200, 150);
815   gfx::Rect copy_rect(200, 150);
816   // Scale the output size so that, internally, scaling is not occurring.
817   gfx::Size output_size =
818       gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
819   bool video_frame = false;
820   PerformTestWithLeftRightRects(html_rect_size,
821                                 copy_rect,
822                                 output_size,
823                                 video_frame);
824 }
825
826 IN_PROC_BROWSER_TEST_P(
827     CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
828     MAYBE_CopyToBitmap_CenterRegion) {
829   gfx::Size html_rect_size(200, 150);
830   // Grab 90x60 pixels from the center of the tab contents.
831   gfx::Rect copy_rect =
832       gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
833                 gfx::Size(90, 60));
834   // Scale the output size so that, internally, scaling is not occurring.
835   gfx::Size output_size =
836       gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
837   bool video_frame = false;
838   PerformTestWithLeftRightRects(html_rect_size,
839                                 copy_rect,
840                                 output_size,
841                                 video_frame);
842 }
843
844 IN_PROC_BROWSER_TEST_P(
845     CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
846     MAYBE_CopyToBitmap_ScaledResult) {
847   gfx::Size html_rect_size(200, 100);
848   gfx::Rect copy_rect(200, 100);
849   // Output is being down-scaled since output_size is in phyiscal pixels.
850   gfx::Size output_size(200, 100);
851   bool video_frame = false;
852   PerformTestWithLeftRightRects(html_rect_size,
853                                 copy_rect,
854                                 output_size,
855                                 video_frame);
856 }
857
858 IN_PROC_BROWSER_TEST_P(
859     CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
860     MAYBE_CopyToVideoFrame_EntireRegion) {
861   gfx::Size html_rect_size(200, 150);
862   gfx::Rect copy_rect(200, 150);
863   // Scale the output size so that, internally, scaling is not occurring.
864   gfx::Size output_size =
865       gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
866   bool video_frame = true;
867   PerformTestWithLeftRightRects(html_rect_size,
868                                 copy_rect,
869                                 output_size,
870                                 video_frame);
871 }
872
873 IN_PROC_BROWSER_TEST_P(
874     CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
875     MAYBE_CopyToVideoFrame_CenterRegion) {
876   gfx::Size html_rect_size(200, 150);
877   // Grab 90x60 pixels from the center of the tab contents.
878   gfx::Rect copy_rect =
879       gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
880                 gfx::Size(90, 60));
881   // Scale the output size so that, internally, scaling is not occurring.
882   gfx::Size output_size =
883       gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
884   bool video_frame = true;
885   PerformTestWithLeftRightRects(html_rect_size,
886                                 copy_rect,
887                                 output_size,
888                                 video_frame);
889 }
890
891 IN_PROC_BROWSER_TEST_P(
892     CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
893     MAYBE_CopyToVideoFrame_ScaledResult) {
894   gfx::Size html_rect_size(200, 100);
895   gfx::Rect copy_rect(200, 100);
896   // Output is being down-scaled since output_size is in phyiscal pixels.
897   gfx::Size output_size(200, 100);
898   bool video_frame = true;
899   PerformTestWithLeftRightRects(html_rect_size,
900                                 copy_rect,
901                                 output_size,
902                                 video_frame);
903 }
904
905 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
906                         CompositingRenderWidgetHostViewBrowserTest,
907                         testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
908 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
909                         CompositingRenderWidgetHostViewBrowserTestTabCapture,
910                         testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
911 INSTANTIATE_TEST_CASE_P(
912     GLAndSoftwareCompositing,
913     CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
914     testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
915
916 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
917
918 }  // namespace
919 }  // namespace content