layer_tree_test.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright 2011 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 "cc/test/layer_tree_test.h"
6
7#include "cc/animation/animation.h"
8#include "cc/animation/animation_registrar.h"
9#include "cc/animation/layer_animation_controller.h"
10#include "cc/animation/timing_function.h"
11#include "cc/base/thread_impl.h"
12#include "cc/input/input_handler.h"
13#include "cc/layers/content_layer.h"
14#include "cc/layers/layer.h"
15#include "cc/layers/layer_impl.h"
16#include "cc/test/animation_test_common.h"
17#include "cc/test/fake_layer_tree_host_client.h"
18#include "cc/test/fake_output_surface.h"
19#include "cc/test/occlusion_tracker_test_common.h"
20#include "cc/test/tiled_layer_test_common.h"
21#include "cc/trees/layer_tree_host_impl.h"
22#include "cc/trees/single_thread_proxy.h"
23#include "testing/gmock/include/gmock/gmock.h"
24#include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperation.h"
25#include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperations.h"
26#include "ui/gfx/size_conversions.h"
27
28using namespace WebKit;
29
30namespace cc {
31
32TestHooks::TestHooks() {
33  fake_client_.reset(
34      new FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D));
35}
36
37TestHooks::~TestHooks() {}
38
39bool TestHooks::PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
40                                      LayerTreeHostImpl::FrameData* frame_data,
41                                      bool result) {
42  return true;
43}
44
45bool TestHooks::CanActivatePendingTree() {
46  return true;
47}
48
49scoped_ptr<OutputSurface> TestHooks::CreateOutputSurface() {
50  return CreateFakeOutputSurface();
51}
52
53scoped_refptr<cc::ContextProvider> TestHooks::
54    OffscreenContextProviderForMainThread() {
55  return fake_client_->OffscreenContextProviderForMainThread();
56}
57
58scoped_refptr<cc::ContextProvider> TestHooks::
59    OffscreenContextProviderForCompositorThread() {
60  return fake_client_->OffscreenContextProviderForCompositorThread();
61}
62
63// Adapts LayerTreeHostImpl for test. Runs real code, then invokes test hooks.
64class LayerTreeHostImplForTesting : public LayerTreeHostImpl {
65 public:
66  typedef std::vector<LayerImpl*> LayerList;
67
68  static scoped_ptr<LayerTreeHostImplForTesting> Create(
69      TestHooks* test_hooks,
70      const LayerTreeSettings& settings,
71      LayerTreeHostImplClient* host_impl_client,
72      Proxy* proxy,
73      RenderingStatsInstrumentation* stats_instrumentation) {
74    return make_scoped_ptr(
75        new LayerTreeHostImplForTesting(test_hooks,
76                                        settings,
77                                        host_impl_client,
78                                        proxy,
79                                        stats_instrumentation));
80  }
81
82 protected:
83  LayerTreeHostImplForTesting(
84      TestHooks* test_hooks,
85      const LayerTreeSettings& settings,
86      LayerTreeHostImplClient* host_impl_client,
87      Proxy* proxy,
88      RenderingStatsInstrumentation* stats_instrumentation)
89      : LayerTreeHostImpl(settings,
90                          host_impl_client,
91                          proxy,
92                          stats_instrumentation),
93        test_hooks_(test_hooks) {}
94
95  virtual void BeginCommit() OVERRIDE {
96    LayerTreeHostImpl::BeginCommit();
97    test_hooks_->BeginCommitOnThread(this);
98  }
99
100  virtual void CommitComplete() OVERRIDE {
101    LayerTreeHostImpl::CommitComplete();
102    test_hooks_->CommitCompleteOnThread(this);
103
104    if (!settings().impl_side_painting)
105      test_hooks_->TreeActivatedOnThread(this);
106  }
107
108  virtual bool PrepareToDraw(FrameData* frame) OVERRIDE {
109    bool result = LayerTreeHostImpl::PrepareToDraw(frame);
110    if (!test_hooks_->PrepareToDrawOnThread(this, frame, result))
111      result = false;
112    return result;
113  }
114
115  virtual void DrawLayers(FrameData* frame,
116                          base::TimeTicks frame_begin_time) OVERRIDE {
117    LayerTreeHostImpl::DrawLayers(frame, frame_begin_time);
118    test_hooks_->DrawLayersOnThread(this);
119  }
120
121  virtual bool SwapBuffers() OVERRIDE {
122    bool result = LayerTreeHostImpl::SwapBuffers();
123    test_hooks_->SwapBuffersOnThread(this, result);
124    return result;
125  }
126
127  virtual bool ActivatePendingTreeIfNeeded() OVERRIDE {
128    if (!pending_tree())
129      return false;
130
131    if (!test_hooks_->CanActivatePendingTree())
132      return false;
133
134    bool activated = LayerTreeHostImpl::ActivatePendingTreeIfNeeded();
135    if (activated)
136      test_hooks_->TreeActivatedOnThread(this);
137    return activated;
138  }
139
140  virtual bool InitializeRenderer(scoped_ptr<OutputSurface> output_surface)
141      OVERRIDE {
142    bool success = LayerTreeHostImpl::InitializeRenderer(output_surface.Pass());
143    test_hooks_->InitializedRendererOnThread(this, success);
144    return success;
145  }
146
147  virtual void SetVisible(bool visible) OVERRIDE {
148    LayerTreeHostImpl::SetVisible(visible);
149    test_hooks_->DidSetVisibleOnImplTree(this, visible);
150  }
151
152  virtual void AnimateLayers(base::TimeTicks monotonic_time,
153                             base::Time wall_clock_time) OVERRIDE {
154    test_hooks_->WillAnimateLayers(this, monotonic_time);
155    LayerTreeHostImpl::AnimateLayers(monotonic_time, wall_clock_time);
156    test_hooks_->AnimateLayers(this, monotonic_time);
157  }
158
159  virtual void UpdateAnimationState() OVERRIDE {
160    LayerTreeHostImpl::UpdateAnimationState();
161    bool has_unfinished_animation = false;
162    AnimationRegistrar::AnimationControllerMap::const_iterator iter =
163        active_animation_controllers().begin();
164    for (; iter != active_animation_controllers().end(); ++iter) {
165      if (iter->second->HasActiveAnimation()) {
166        has_unfinished_animation = true;
167        break;
168      }
169    }
170    test_hooks_->UpdateAnimationState(this, has_unfinished_animation);
171  }
172
173  virtual base::TimeDelta LowFrequencyAnimationInterval() const OVERRIDE {
174    return base::TimeDelta::FromMilliseconds(16);
175  }
176
177 private:
178  TestHooks* test_hooks_;
179};
180
181// Adapts LayerTreeHost for test. Injects LayerTreeHostImplForTesting.
182class LayerTreeHostForTesting : public cc::LayerTreeHost {
183 public:
184  static scoped_ptr<LayerTreeHostForTesting> Create(
185      TestHooks* test_hooks,
186      cc::LayerTreeHostClient* host_client,
187      const cc::LayerTreeSettings& settings,
188      scoped_ptr<cc::Thread> impl_thread) {
189    scoped_ptr<LayerTreeHostForTesting> layer_tree_host(
190        new LayerTreeHostForTesting(test_hooks, host_client, settings));
191    bool success = layer_tree_host->Initialize(impl_thread.Pass());
192    EXPECT_TRUE(success);
193    return layer_tree_host.Pass();
194  }
195
196  virtual scoped_ptr<cc::LayerTreeHostImpl> CreateLayerTreeHostImpl(
197      cc::LayerTreeHostImplClient* host_impl_client) OVERRIDE {
198    return LayerTreeHostImplForTesting::Create(
199        test_hooks_,
200        settings(),
201        host_impl_client,
202        proxy(),
203        rendering_stats_instrumentation()).PassAs<cc::LayerTreeHostImpl>();
204  }
205
206  virtual void SetNeedsCommit() OVERRIDE {
207    if (!test_started_)
208      return;
209    LayerTreeHost::SetNeedsCommit();
210  }
211
212  void set_test_started(bool started) { test_started_ = started; }
213
214  virtual void DidDeferCommit() OVERRIDE {
215    test_hooks_->DidDeferCommit();
216  }
217
218 private:
219  LayerTreeHostForTesting(TestHooks* test_hooks,
220                          cc::LayerTreeHostClient* client,
221                          const cc::LayerTreeSettings& settings)
222      : LayerTreeHost(client, settings),
223        test_hooks_(test_hooks),
224        test_started_(false) {}
225
226  TestHooks* test_hooks_;
227  bool test_started_;
228};
229
230// Implementation of LayerTreeHost callback interface.
231class LayerTreeHostClientForTesting : public LayerTreeHostClient {
232 public:
233  static scoped_ptr<LayerTreeHostClientForTesting> Create(
234      TestHooks* test_hooks) {
235    return make_scoped_ptr(new LayerTreeHostClientForTesting(test_hooks));
236  }
237  virtual ~LayerTreeHostClientForTesting() {}
238
239  virtual void WillBeginFrame() OVERRIDE {}
240
241  virtual void DidBeginFrame() OVERRIDE {}
242
243  virtual void Animate(double monotonic_time) OVERRIDE {
244    test_hooks_->Animate(base::TimeTicks::FromInternalValue(
245        monotonic_time * base::Time::kMicrosecondsPerSecond));
246  }
247
248  virtual void Layout() OVERRIDE {
249    test_hooks_->Layout();
250  }
251
252  virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
253                                   float scale) OVERRIDE {
254    test_hooks_->ApplyScrollAndScale(scroll_delta, scale);
255  }
256
257  virtual scoped_ptr<OutputSurface> CreateOutputSurface() OVERRIDE {
258    return test_hooks_->CreateOutputSurface();
259  }
260
261  virtual void DidRecreateOutputSurface(bool succeeded) OVERRIDE {
262    test_hooks_->DidRecreateOutputSurface(succeeded);
263  }
264
265  virtual void WillRetryRecreateOutputSurface() OVERRIDE {
266    test_hooks_->WillRetryRecreateOutputSurface();
267  }
268
269  virtual scoped_ptr<InputHandler> CreateInputHandler() OVERRIDE {
270    return scoped_ptr<InputHandler>();
271  }
272
273  virtual void WillCommit() OVERRIDE {}
274
275  virtual void DidCommit() OVERRIDE {
276    test_hooks_->DidCommit();
277  }
278
279  virtual void DidCommitAndDrawFrame() OVERRIDE {
280    test_hooks_->DidCommitAndDrawFrame();
281  }
282
283  virtual void DidCompleteSwapBuffers() OVERRIDE {}
284
285  virtual void ScheduleComposite() OVERRIDE {
286    test_hooks_->ScheduleComposite();
287  }
288
289  virtual scoped_refptr<cc::ContextProvider>
290      OffscreenContextProviderForMainThread() OVERRIDE {
291    return test_hooks_->OffscreenContextProviderForMainThread();
292  }
293
294  virtual scoped_refptr<cc::ContextProvider>
295      OffscreenContextProviderForCompositorThread() OVERRIDE {
296    return test_hooks_->OffscreenContextProviderForCompositorThread();
297  }
298
299 private:
300  explicit LayerTreeHostClientForTesting(TestHooks* test_hooks)
301      : test_hooks_(test_hooks) {}
302
303  TestHooks* test_hooks_;
304};
305
306LayerTreeTest::LayerTreeTest()
307    : beginning_(false),
308      end_when_begin_returns_(false),
309      timed_out_(false),
310      scheduled_(false),
311      schedule_when_set_visible_true_(false),
312      started_(false),
313      ended_(false),
314      impl_thread_(NULL),
315      weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
316  main_thread_weak_ptr_ = weak_factory_.GetWeakPtr();
317}
318
319LayerTreeTest::~LayerTreeTest() {}
320
321void LayerTreeTest::EndTest() {
322  // For the case where we EndTest during BeginTest(), set a flag to indicate
323  // that the test should end the second BeginTest regains control.
324  if (beginning_) {
325    end_when_begin_returns_ = true;
326  } else if (proxy()) {
327    // Racy timeouts and explicit EndTest calls might have cleaned up
328    // the tree host. Should check proxy first.
329    proxy()->MainThread()->PostTask(
330        base::Bind(&LayerTreeTest::RealEndTest, main_thread_weak_ptr_));
331  }
332}
333
334void LayerTreeTest::EndTestAfterDelay(int delay_milliseconds) {
335  proxy()->MainThread()->PostTask(
336      base::Bind(&LayerTreeTest::EndTest, main_thread_weak_ptr_));
337}
338
339void LayerTreeTest::PostAddAnimationToMainThread(
340    Layer* layer_to_receive_animation) {
341  proxy()->MainThread()->PostTask(
342      base::Bind(&LayerTreeTest::DispatchAddAnimation,
343                 main_thread_weak_ptr_,
344                 base::Unretained(layer_to_receive_animation)));
345}
346
347void LayerTreeTest::PostAddInstantAnimationToMainThread() {
348  proxy()->MainThread()->PostTask(
349      base::Bind(&LayerTreeTest::DispatchAddInstantAnimation,
350                 main_thread_weak_ptr_));
351}
352
353void LayerTreeTest::PostSetNeedsCommitToMainThread() {
354  proxy()->MainThread()->PostTask(
355      base::Bind(&LayerTreeTest::DispatchSetNeedsCommit,
356                 main_thread_weak_ptr_));
357}
358
359void LayerTreeTest::PostAcquireLayerTextures() {
360  proxy()->MainThread()->PostTask(
361      base::Bind(&LayerTreeTest::DispatchAcquireLayerTextures,
362                 main_thread_weak_ptr_));
363}
364
365void LayerTreeTest::PostSetNeedsRedrawToMainThread() {
366  proxy()->MainThread()->PostTask(
367      base::Bind(&LayerTreeTest::DispatchSetNeedsRedraw,
368                 main_thread_weak_ptr_));
369}
370
371void LayerTreeTest::PostSetVisibleToMainThread(bool visible) {
372  proxy()->MainThread()->PostTask(
373      base::Bind(&LayerTreeTest::DispatchSetVisible,
374                 main_thread_weak_ptr_,
375                 visible));
376}
377
378void LayerTreeTest::DoBeginTest() {
379  client_ = LayerTreeHostClientForTesting::Create(this);
380
381  scoped_ptr<cc::Thread> impl_ccthread(NULL);
382  if (impl_thread_) {
383    impl_ccthread = cc::ThreadImpl::CreateForDifferentThread(
384        impl_thread_->message_loop_proxy());
385  }
386  layer_tree_host_ = LayerTreeHostForTesting::Create(this,
387                                                     client_.get(),
388                                                     settings_,
389                                                     impl_ccthread.Pass());
390  ASSERT_TRUE(layer_tree_host_);
391
392  started_ = true;
393  beginning_ = true;
394  SetupTree();
395  layer_tree_host_->SetSurfaceReady();
396  BeginTest();
397  beginning_ = false;
398  if (end_when_begin_returns_)
399    RealEndTest();
400
401  // Allow commits to happen once BeginTest() has had a chance to post tasks
402  // so that those tasks will happen before the first commit.
403  if (layer_tree_host_) {
404    static_cast<LayerTreeHostForTesting*>(layer_tree_host_.get())->
405        set_test_started(true);
406  }
407}
408
409void LayerTreeTest::SetupTree() {
410  if (!layer_tree_host_->root_layer()) {
411    scoped_refptr<Layer> root_layer = Layer::Create();
412    root_layer->SetBounds(gfx::Size(1, 1));
413    layer_tree_host_->SetRootLayer(root_layer);
414  }
415
416  gfx::Size root_bounds = layer_tree_host_->root_layer()->bounds();
417  gfx::Size device_root_bounds = gfx::ToCeiledSize(
418      gfx::ScaleSize(root_bounds, layer_tree_host_->device_scale_factor()));
419  layer_tree_host_->SetViewportSize(root_bounds, device_root_bounds);
420}
421
422void LayerTreeTest::Timeout() {
423  timed_out_ = true;
424  EndTest();
425}
426
427void LayerTreeTest::ScheduleComposite() {
428  if (!started_ || scheduled_)
429    return;
430  scheduled_ = true;
431  proxy()->MainThread()->PostTask(
432      base::Bind(&LayerTreeTest::DispatchComposite, main_thread_weak_ptr_));
433}
434
435void LayerTreeTest::RealEndTest() {
436  ended_ = true;
437
438  if (layer_tree_host_ && proxy()->CommitPendingForTesting()) {
439    proxy()->MainThread()->PostTask(
440        base::Bind(&LayerTreeTest::RealEndTest, main_thread_weak_ptr_));
441    return;
442  }
443
444  MessageLoop::current()->Quit();
445}
446
447void LayerTreeTest::DispatchAddInstantAnimation() {
448  DCHECK(!proxy() || proxy()->IsMainThread());
449
450  if (layer_tree_host_.get() && layer_tree_host_->root_layer()) {
451    AddOpacityTransitionToLayer(layer_tree_host_->root_layer(),
452                                0,
453                                0,
454                                0.5,
455                                false);
456  }
457}
458
459void LayerTreeTest::DispatchAddAnimation(Layer* layer_to_receive_animation) {
460  DCHECK(!proxy() || proxy()->IsMainThread());
461
462  if (layer_to_receive_animation)
463    AddOpacityTransitionToLayer(layer_to_receive_animation, 10, 0, 0.5, true);
464}
465
466void LayerTreeTest::DispatchSetNeedsCommit() {
467  DCHECK(!proxy() || proxy()->IsMainThread());
468
469  if (layer_tree_host_)
470    layer_tree_host_->SetNeedsCommit();
471}
472
473void LayerTreeTest::DispatchAcquireLayerTextures() {
474  DCHECK(!proxy() || proxy()->IsMainThread());
475
476  if (layer_tree_host_)
477    layer_tree_host_->AcquireLayerTextures();
478}
479
480void LayerTreeTest::DispatchSetNeedsRedraw() {
481  DCHECK(!proxy() || proxy()->IsMainThread());
482
483  if (layer_tree_host_)
484    layer_tree_host_->SetNeedsRedraw();
485}
486
487void LayerTreeTest::DispatchSetVisible(bool visible) {
488  DCHECK(!proxy() || proxy()->IsMainThread());
489
490  if (!layer_tree_host_)
491    return;
492
493  layer_tree_host_->SetVisible(visible);
494
495  // If the LTH is being made visible and a previous ScheduleComposite() was
496  // deferred because the LTH was not visible, re-schedule the composite now.
497  if (layer_tree_host_->visible() && schedule_when_set_visible_true_)
498    ScheduleComposite();
499}
500
501void LayerTreeTest::DispatchComposite() {
502  scheduled_ = false;
503
504  if (!layer_tree_host_)
505    return;
506
507  // If the LTH is not visible, defer the composite until the LTH is made
508  // visible.
509  if (!layer_tree_host_->visible()) {
510    schedule_when_set_visible_true_ = true;
511    return;
512  }
513
514  schedule_when_set_visible_true_ = false;
515  layer_tree_host_->Composite(base::TimeTicks::Now());
516}
517
518void LayerTreeTest::RunTest(bool threaded) {
519  if (threaded) {
520    impl_thread_.reset(new base::Thread("LayerTreeTest"));
521    ASSERT_TRUE(impl_thread_->Start());
522  }
523
524  main_ccthread_ = cc::ThreadImpl::CreateForCurrentThread();
525
526  InitializeSettings(&settings_);
527
528  main_ccthread_->PostTask(
529      base::Bind(&LayerTreeTest::DoBeginTest, base::Unretained(this)));
530  timeout_.Reset(base::Bind(&LayerTreeTest::Timeout, base::Unretained(this)));
531  main_ccthread_->PostDelayedTask(timeout_.callback(),
532                                  base::TimeDelta::FromSeconds(5));
533  MessageLoop::current()->Run();
534  if (layer_tree_host_ && layer_tree_host_->root_layer())
535    layer_tree_host_->root_layer()->SetLayerTreeHost(NULL);
536  layer_tree_host_.reset();
537
538  timeout_.Cancel();
539
540  ASSERT_FALSE(layer_tree_host_.get());
541  client_.reset();
542  if (timed_out_) {
543    FAIL() << "Test timed out";
544    return;
545  }
546  AfterTest();
547}
548
549}  // namespace cc
550