This source file includes following definitions.
- fallback_context_works_
 
- LoseContext
 
- CreateContext3d
 
- CreateFakeOutputSurface
 
- CreateOffscreenContext3d
 
- OffscreenContextProvider
 
- PrepareToDrawOnThread
 
- CommitCompleteOnThread
 
- DidFailToInitializeOutputSurface
 
- TearDown
 
- ExpectCreateToFail
 
- first_initialized_
 
- BeginTest
 
- DidInitializeOutputSurface
 
- AfterTest
 
- DidCommitAndDrawFrame
 
- InvalidateAndSetNeedsCommit
 
- NextTestCase
 
- WillBeginTest
 
- BeginTest
 
- CreateOutputSurface
 
- DidInitializeOutputSurface
 
- AfterTest
 
- SetupTree
 
- InvalidateAndSetNeedsCommit
 
- DrawLayersOnThread
 
- AfterTest
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- times_initialized_
 
- BeginTest
 
- CreateFakeOutputSurface
 
- DidInitializeOutputSurface
 
- DrawLayersOnThread
 
- AfterTest
 
- SetupTree
 
- BeginTest
 
- DrawLayersOnThread
 
- AfterTest
 
- first_initialized_
 
- BeginTest
 
- DidInitializeOutputSurface
 
- CommitCompleteOnThread
 
- AfterTest
 
- num_commits_
 
- SetupTree
 
- BeginTest
 
- PostEvictTextures
 
- EvictTexturesOnImplThread
 
- DidCommitAndDrawFrame
 
- CommitCompleteOnThread
 
- DidInitializeOutputSurface
 
- AfterTest
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- times_to_lose_on_end_query_
 
- CreateContext3d
 
- SetupTree
 
- BeginTest
 
- DrawLayersOnThread
 
- DidInitializeOutputSurface
 
- AfterTest
 
- num_commits_
 
- SetupTree
 
- BeginTest
 
- DidActivateTreeOnThread
 
- AfterTest
 
- EmptyReleaseCallback
 
- SetupTree
 
- BeginTest
 
- CommitCompleteOnThread
 
- PrepareToDrawOnThread
 
- CreateFakeOutputSurface
 
- DidCommitAndDrawFrame
 
- AfterTest
 
- BeginTest
 
- DidInitializeOutputSurface
 
- DidCommitAndDrawFrame
 
- AfterTest
 
- PrepareToDrawOnThread
 
- DrawLayersOnThread
 
- SwapBuffersOnThread
 
- InitializeSettings
 
- BeginTest
 
- PrepareToDrawOnThread
 
- InitializedRendererOnThread
 
- DrawLayersOnThread
 
- SwapBuffersOnThread
 
- AfterTest
 
- InitializeSettings
 
- BeginTest
 
- PrepareToDrawOnThread
 
- DidInitializeOutputSurface
 
- InitializedRendererOnThread
 
- DrawLayersOnThread
 
- SwapBuffersOnThread
 
- AfterTest
 
- InitializeSettings
 
- SetupTree
 
- BeginTest
 
- AfterTest
 
- DidInitializeOutputSurface
 
- BeginTest
 
- AfterTest
 
- CommitCompleteOnThread
 
- InitializeSettings
 
- BeginTest
 
- AfterTest
 
- PostStepCompleteToMainThread
 
- PostLoseContextToImplThread
 
- StepCompleteOnMainThreadInternal
 
- CommitCompleteOnThread
 
- DidActivateTreeOnThread
 
- StepCompleteOnMainThread
 
- StepCompleteOnImplThread
 
- test_id1_
 
- StepCompleteOnMainThread
 
- StepCompleteOnImplThread
 
- StepCompleteOnMainThread
 
- CommitCompleteOnThread
 
- WillActivateTreeOnThread
 
- DidActivateTreeOnThread
 
- TEST_F
 
- TEST_F
 
- StepCompleteOnMainThread
 
- DidSetVisibleOnImplTree
 
- StepCompleteOnImplThread
 
- layer_
 
- SetupTree
 
- BeginTest
 
- DidCommit
 
- CommitCompleteOnThread
 
- DidInitializeOutputSurface
 
- AfterTest
 
#include "cc/trees/layer_tree_host.h"
#include "base/basictypes.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/delegated_frame_provider.h"
#include "cc/layers/delegated_frame_resource_collection.h"
#include "cc/layers/heads_up_display_layer.h"
#include "cc/layers/io_surface_layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/painted_scrollbar_layer.h"
#include "cc/layers/picture_layer.h"
#include "cc/layers/texture_layer.h"
#include "cc/layers/texture_layer_impl.h"
#include "cc/layers/video_layer.h"
#include "cc/layers/video_layer_impl.h"
#include "cc/output/filter_operations.h"
#include "cc/test/fake_content_layer.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_content_layer_impl.h"
#include "cc/test/fake_delegated_renderer_layer.h"
#include "cc/test/fake_delegated_renderer_layer_impl.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_painted_scrollbar_layer.h"
#include "cc/test/fake_scoped_ui_resource.h"
#include "cc/test/fake_scrollbar.h"
#include "cc/test/fake_video_frame_provider.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/test_context_provider.h"
#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "media/base/media.h"
using media::VideoFrame;
namespace cc {
namespace {
class LayerTreeHostContextTest : public LayerTreeTest {
 public:
  LayerTreeHostContextTest()
      : LayerTreeTest(),
        context3d_(NULL),
        times_to_fail_create_(0),
        times_to_lose_during_commit_(0),
        times_to_lose_during_draw_(0),
        times_to_fail_recreate_(0),
        times_to_fail_create_offscreen_(0),
        times_to_fail_recreate_offscreen_(0),
        times_to_expect_create_failed_(0),
        times_create_failed_(0),
        times_offscreen_created_(0),
        committed_at_least_once_(false),
        context_should_support_io_surface_(false),
        fallback_context_works_(false) {
    media::InitializeMediaLibraryForTesting();
  }
  void LoseContext() {
    context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
                                    GL_INNOCENT_CONTEXT_RESET_ARB);
    context3d_ = NULL;
  }
  virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
    return TestWebGraphicsContext3D::Create();
  }
  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
      OVERRIDE {
    if (times_to_fail_create_) {
      --times_to_fail_create_;
      ExpectCreateToFail();
      return scoped_ptr<FakeOutputSurface>();
    }
    scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
    context3d_ = context3d.get();
    if (context_should_support_io_surface_) {
      context3d_->set_have_extension_io_surface(true);
      context3d_->set_have_extension_egl_image(true);
    }
    if (delegating_renderer())
      return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
    else
      return FakeOutputSurface::Create3d(context3d.Pass());
  }
  scoped_ptr<TestWebGraphicsContext3D> CreateOffscreenContext3d() {
    if (!context3d_)
      return scoped_ptr<TestWebGraphicsContext3D>();
    ++times_offscreen_created_;
    if (times_to_fail_create_offscreen_) {
      --times_to_fail_create_offscreen_;
      ExpectCreateToFail();
      return scoped_ptr<TestWebGraphicsContext3D>();
    }
    scoped_ptr<TestWebGraphicsContext3D> offscreen_context3d =
        TestWebGraphicsContext3D::Create().Pass();
    DCHECK(offscreen_context3d);
    context3d_->add_share_group_context(offscreen_context3d.get());
    return offscreen_context3d.Pass();
  }
  virtual scoped_refptr<ContextProvider> OffscreenContextProvider() OVERRIDE {
    if (!offscreen_contexts_.get() ||
        offscreen_contexts_->DestroyedOnMainThread()) {
      offscreen_contexts_ =
          TestContextProvider::Create(CreateOffscreenContext3d());
    }
    return offscreen_contexts_;
  }
  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
      LayerTreeHostImpl* host_impl,
      LayerTreeHostImpl::FrameData* frame,
      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
    EXPECT_EQ(DrawSwapReadbackResult::DRAW_SUCCESS, draw_result);
    if (!times_to_lose_during_draw_)
      return draw_result;
    --times_to_lose_during_draw_;
    LoseContext();
    times_to_fail_create_ = times_to_fail_recreate_;
    times_to_fail_recreate_ = 0;
    times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
    times_to_fail_recreate_offscreen_ = 0;
    return draw_result;
  }
  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    committed_at_least_once_ = true;
    if (!times_to_lose_during_commit_)
      return;
    --times_to_lose_during_commit_;
    LoseContext();
    times_to_fail_create_ = times_to_fail_recreate_;
    times_to_fail_recreate_ = 0;
    times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
    times_to_fail_recreate_offscreen_ = 0;
  }
  virtual void DidFailToInitializeOutputSurface() OVERRIDE {
    ++times_create_failed_;
  }
  virtual void TearDown() OVERRIDE {
    LayerTreeTest::TearDown();
    EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
  }
  void ExpectCreateToFail() { ++times_to_expect_create_failed_; }
 protected:
  TestWebGraphicsContext3D* context3d_;
  int times_to_fail_create_;
  int times_to_lose_during_commit_;
  int times_to_lose_during_draw_;
  int times_to_fail_recreate_;
  int times_to_fail_create_offscreen_;
  int times_to_fail_recreate_offscreen_;
  int times_to_expect_create_failed_;
  int times_create_failed_;
  int times_offscreen_created_;
  bool committed_at_least_once_;
  bool context_should_support_io_surface_;
  bool fallback_context_works_;
  scoped_refptr<TestContextProvider> offscreen_contexts_;
};
class LayerTreeHostContextTestLostContextSucceeds
    : public LayerTreeHostContextTest {
 public:
  LayerTreeHostContextTestLostContextSucceeds()
      : LayerTreeHostContextTest(),
        test_case_(0),
        num_losses_(0),
        num_losses_last_test_case_(-1),
        recovered_context_(true),
        first_initialized_(false) {}
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    EXPECT_TRUE(succeeded);
    if (first_initialized_)
      ++num_losses_;
    else
      first_initialized_ = true;
    recovered_context_ = true;
  }
  virtual void AfterTest() OVERRIDE { EXPECT_EQ(9u, test_case_); }
  virtual void DidCommitAndDrawFrame() OVERRIDE {
    
    
    if (!recovered_context_)
      return;
    if (times_to_lose_during_commit_)
      return;
    if (times_to_lose_during_draw_)
      return;
    recovered_context_ = false;
    if (NextTestCase())
      InvalidateAndSetNeedsCommit();
    else
      EndTest();
  }
  virtual void InvalidateAndSetNeedsCommit() {
    
    layer_tree_host()->root_layer()->SetNeedsDisplay();
    layer_tree_host()->SetNeedsCommit();
  }
  bool NextTestCase() {
    static const TestCase kTests[] = {
        
        
        {1,      
         0,      
         0,      
         0,      
         false,  
        },
        {0,      
         1,      
         0,      
         0,      
         false,  
        },
        {1,      
         0,      
         3,      
         0,      
         false,  
        },
        {0,      
         1,      
         3,      
         0,      
         false,  
        },
        {1,      
         0,      
         0,      
         3,      
         false,  
        },
        {0,      
         1,      
         0,      
         3,      
         false,  
        },
        
        
        {10,     
         0,      
         0,      
         0,      
         false,  
        },
        {0,      
         10,     
         0,      
         0,      
         false,  
        },
        
        
        {0,     
         1,     
         0,     
         0,     
         true,  
        }, };
    if (test_case_ >= arraysize(kTests))
      return false;
    
    
    EXPECT_GT(num_losses_, num_losses_last_test_case_);
    num_losses_last_test_case_ = num_losses_;
    times_to_lose_during_commit_ =
        kTests[test_case_].times_to_lose_during_commit;
    times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw;
    times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
    times_to_fail_recreate_offscreen_ =
        kTests[test_case_].times_to_fail_recreate_offscreen;
    fallback_context_works_ = kTests[test_case_].fallback_context_works;
    ++test_case_;
    return true;
  }
  struct TestCase {
    int times_to_lose_during_commit;
    int times_to_lose_during_draw;
    int times_to_fail_recreate;
    int times_to_fail_recreate_offscreen;
    bool fallback_context_works;
  };
 protected:
  size_t test_case_;
  int num_losses_;
  int num_losses_last_test_case_;
  bool recovered_context_;
  bool first_initialized_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
    : public LayerTreeHostContextTest {
 public:
  LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
      : LayerTreeHostContextTest() {}
  virtual void WillBeginTest() OVERRIDE {
    
  }
  virtual void BeginTest() OVERRIDE {
    PostSetNeedsCommitToMainThread();
    EndTest();
  }
  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
      OVERRIDE {
    EXPECT_TRUE(false);
    return scoped_ptr<OutputSurface>();
  }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    EXPECT_TRUE(false);
  }
  virtual void AfterTest() OVERRIDE {
  }
};
MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
class LayerTreeHostContextTestLostContextSucceedsWithContent
    : public LayerTreeHostContextTestLostContextSucceeds {
 public:
  LayerTreeHostContextTestLostContextSucceedsWithContent()
      : LayerTreeHostContextTestLostContextSucceeds() {}
  virtual void SetupTree() OVERRIDE {
    root_ = Layer::Create();
    root_->SetBounds(gfx::Size(10, 10));
    root_->SetAnchorPoint(gfx::PointF());
    root_->SetIsDrawable(true);
    content_ = FakeContentLayer::Create(&client_);
    content_->SetBounds(gfx::Size(10, 10));
    content_->SetAnchorPoint(gfx::PointF());
    content_->SetIsDrawable(true);
    if (use_surface_) {
      content_->SetForceRenderSurface(true);
      
      FilterOperations filters;
      filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
      content_->SetFilters(filters);
      content_->SetBackgroundFilters(filters);
    }
    root_->AddChild(content_);
    layer_tree_host()->SetRootLayer(root_);
    LayerTreeHostContextTest::SetupTree();
  }
  virtual void InvalidateAndSetNeedsCommit() OVERRIDE {
    
    
    
    content_->SetNeedsDisplay();
    LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
  }
  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
        host_impl->active_tree()->root_layer()->children()[0]);
    
    
    
    EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
    ContextProvider* contexts = host_impl->offscreen_context_provider();
    if (use_surface_) {
      ASSERT_TRUE(contexts);
      EXPECT_TRUE(contexts->ContextGL());
      
      
    } else {
      EXPECT_FALSE(contexts);
    }
  }
  virtual void AfterTest() OVERRIDE {
    LayerTreeHostContextTestLostContextSucceeds::AfterTest();
    if (use_surface_) {
      
      
      
      
      
      EXPECT_EQ(4 + 1 + 2 + num_losses_, times_offscreen_created_);
    } else {
      EXPECT_EQ(0, times_offscreen_created_);
    }
  }
 protected:
  bool use_surface_;
  FakeContentLayerClient client_;
  scoped_refptr<Layer> root_;
  scoped_refptr<ContentLayer> content_;
};
TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
       NoSurface_SingleThread_DirectRenderer) {
  use_surface_ = false;
  RunTest(false, false, false);
}
TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
       NoSurface_SingleThread_DelegatingRenderer) {
  use_surface_ = false;
  RunTest(false, true, false);
}
TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
       NoSurface_MultiThread_DirectRenderer_MainThreadPaint) {
  use_surface_ = false;
  RunTest(true, false, false);
}
TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
       NoSurface_MultiThread_DelegatingRenderer_MainThreadPaint) {
  use_surface_ = false;
  RunTest(true, true, false);
}
TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
       WithSurface_SingleThread_DirectRenderer) {
  use_surface_ = true;
  RunTest(false, false, false);
}
TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
       WithSurface_MultiThread_DirectRenderer_MainThreadPaint) {
  use_surface_ = true;
  RunTest(true, false, false);
}
class LayerTreeHostContextTestCreateOutputSurfaceFails
    : public LayerTreeHostContextTest {
 public:
  
  
  
  LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
                                                   bool expect_fallback_attempt,
                                                   bool expect_to_give_up)
      : times_to_fail_(times_to_fail),
        expect_fallback_attempt_(expect_fallback_attempt),
        expect_to_give_up_(expect_to_give_up),
        did_attempt_fallback_(false),
        times_initialized_(0) {}
  virtual void BeginTest() OVERRIDE {
    times_to_fail_create_ = times_to_fail_;
    PostSetNeedsCommitToMainThread();
  }
  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
      OVERRIDE {
    scoped_ptr<FakeOutputSurface> surface =
        LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
    if (surface)
      EXPECT_EQ(times_to_fail_, times_create_failed_);
    did_attempt_fallback_ = fallback;
    return surface.Pass();
  }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    if (succeeded)
      times_initialized_++;
    else
      EndTest();
  }
  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    EndTest();
  }
  virtual void AfterTest() OVERRIDE {
    EXPECT_EQ(times_to_fail_, times_create_failed_);
    EXPECT_EQ(expect_to_give_up_, times_initialized_ == 0);
    EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
  }
 private:
  int times_to_fail_;
  bool expect_fallback_attempt_;
  bool expect_to_give_up_;
  bool did_attempt_fallback_;
  int times_initialized_;
};
class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
    : public LayerTreeHostContextTestCreateOutputSurfaceFails {
 public:
  LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
      : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false, false) {}
};
SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
    : public LayerTreeHostContextTestCreateOutputSurfaceFails {
 public:
  LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
      : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true, false) {}
};
SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
class LayerTreeHostContextTestCreateOutputSurfaceIsHopeless
    : public LayerTreeHostContextTestCreateOutputSurfaceFails {
 public:
  LayerTreeHostContextTestCreateOutputSurfaceIsHopeless()
      : LayerTreeHostContextTestCreateOutputSurfaceFails(5, true, true) {}
};
SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostContextTestCreateOutputSurfaceIsHopeless);
class LayerTreeHostContextTestOffscreenContextFails
    : public LayerTreeHostContextTest {
 public:
  virtual void SetupTree() OVERRIDE {
    root_ = Layer::Create();
    root_->SetBounds(gfx::Size(10, 10));
    root_->SetAnchorPoint(gfx::PointF());
    root_->SetIsDrawable(true);
    content_ = FakeContentLayer::Create(&client_);
    content_->SetBounds(gfx::Size(10, 10));
    content_->SetAnchorPoint(gfx::PointF());
    content_->SetIsDrawable(true);
    content_->SetForceRenderSurface(true);
    
    FilterOperations filters;
    filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
    content_->SetFilters(filters);
    content_->SetBackgroundFilters(filters);
    root_->AddChild(content_);
    layer_tree_host()->SetRootLayer(root_);
    LayerTreeHostContextTest::SetupTree();
  }
  virtual void BeginTest() OVERRIDE {
    times_to_fail_create_offscreen_ = 1;
    PostSetNeedsCommitToMainThread();
  }
  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    ContextProvider* contexts = host_impl->offscreen_context_provider();
    EXPECT_FALSE(contexts);
    
    times_to_expect_create_failed_ = 0;
    EndTest();
  }
  virtual void AfterTest() OVERRIDE {}
 protected:
  FakeContentLayerClient client_;
  scoped_refptr<Layer> root_;
  scoped_refptr<ContentLayer> content_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails);
class LayerTreeHostContextTestLostContextFails
    : public LayerTreeHostContextTest {
 public:
  LayerTreeHostContextTestLostContextFails()
      : LayerTreeHostContextTest(), num_commits_(0), first_initialized_(false) {
    times_to_lose_during_commit_ = 1;
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    if (first_initialized_) {
      EXPECT_FALSE(succeeded);
      EndTest();
    } else {
      first_initialized_ = true;
    }
  }
  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
    ++num_commits_;
    if (num_commits_ == 1) {
      
      EXPECT_TRUE(host_impl->output_surface());
      EXPECT_TRUE(host_impl->renderer());
      EXPECT_TRUE(host_impl->resource_provider());
      return;
    }
    
    EXPECT_FALSE(host_impl->output_surface());
    EXPECT_FALSE(host_impl->renderer());
    EXPECT_FALSE(host_impl->resource_provider());
  }
  virtual void AfterTest() OVERRIDE {}
 private:
  int num_commits_;
  bool first_initialized_;
};
class LayerTreeHostContextTestLostContextAndEvictTextures
    : public LayerTreeHostContextTest {
 public:
  LayerTreeHostContextTestLostContextAndEvictTextures()
      : LayerTreeHostContextTest(),
        layer_(FakeContentLayer::Create(&client_)),
        impl_host_(0),
        num_commits_(0) {}
  virtual void SetupTree() OVERRIDE {
    layer_->SetBounds(gfx::Size(10, 20));
    layer_tree_host()->SetRootLayer(layer_);
    LayerTreeHostContextTest::SetupTree();
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  void PostEvictTextures() {
    if (HasImplThread()) {
      ImplThreadTaskRunner()->PostTask(
          FROM_HERE,
          base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
                          EvictTexturesOnImplThread,
                     base::Unretained(this)));
    } else {
      DebugScopedSetImplThread impl(proxy());
      EvictTexturesOnImplThread();
    }
  }
  void EvictTexturesOnImplThread() {
    impl_host_->EvictTexturesForTesting();
    if (lose_after_evict_)
      LoseContext();
  }
  virtual void DidCommitAndDrawFrame() OVERRIDE {
    if (num_commits_ > 1)
      return;
    EXPECT_TRUE(layer_->HaveBackingAt(0, 0));
    PostEvictTextures();
  }
  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
    if (num_commits_ > 1)
      return;
    ++num_commits_;
    if (!lose_after_evict_)
      LoseContext();
    impl_host_ = impl;
  }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    EXPECT_TRUE(succeeded);
    EndTest();
  }
  virtual void AfterTest() OVERRIDE {}
 protected:
  bool lose_after_evict_;
  FakeContentLayerClient client_;
  scoped_refptr<FakeContentLayer> layer_;
  LayerTreeHostImpl* impl_host_;
  int num_commits_;
};
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseAfterEvict_SingleThread_DirectRenderer) {
  lose_after_evict_ = true;
  RunTest(false, false, false);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseAfterEvict_SingleThread_DelegatingRenderer) {
  lose_after_evict_ = true;
  RunTest(false, true, false);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
  lose_after_evict_ = true;
  RunTest(true, false, false);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
  lose_after_evict_ = true;
  RunTest(true, true, false);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
  lose_after_evict_ = true;
  RunTest(true, true, true);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseBeforeEvict_SingleThread_DirectRenderer) {
  lose_after_evict_ = false;
  RunTest(false, false, false);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseBeforeEvict_SingleThread_DelegatingRenderer) {
  lose_after_evict_ = false;
  RunTest(false, true, false);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
  lose_after_evict_ = false;
  RunTest(true, false, false);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
  lose_after_evict_ = false;
  RunTest(true, false, true);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
  lose_after_evict_ = false;
  RunTest(true, true, false);
}
TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
       LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
  lose_after_evict_ = false;
  RunTest(true, true, true);
}
class LayerTreeHostContextTestLostContextWhileUpdatingResources
    : public LayerTreeHostContextTest {
 public:
  LayerTreeHostContextTestLostContextWhileUpdatingResources()
      : parent_(FakeContentLayer::Create(&client_)),
        num_children_(50),
        times_to_lose_on_end_query_(3) {}
  virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() OVERRIDE {
    scoped_ptr<TestWebGraphicsContext3D> context =
        LayerTreeHostContextTest::CreateContext3d();
    if (times_to_lose_on_end_query_) {
      --times_to_lose_on_end_query_;
      context->set_times_end_query_succeeds(5);
    }
    return context.Pass();
  }
  virtual void SetupTree() OVERRIDE {
    parent_->SetBounds(gfx::Size(num_children_, 1));
    for (int i = 0; i < num_children_; i++) {
      scoped_refptr<FakeContentLayer> child =
          FakeContentLayer::Create(&client_);
      child->SetPosition(gfx::PointF(i, 0.f));
      child->SetBounds(gfx::Size(1, 1));
      parent_->AddChild(child);
    }
    layer_tree_host()->SetRootLayer(parent_);
    LayerTreeHostContextTest::SetupTree();
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    EXPECT_EQ(0, times_to_lose_on_end_query_);
    EndTest();
  }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    EXPECT_TRUE(succeeded);
  }
  virtual void AfterTest() OVERRIDE {
    EXPECT_EQ(0, times_to_lose_on_end_query_);
  }
 private:
  FakeContentLayerClient client_;
  scoped_refptr<FakeContentLayer> parent_;
  int num_children_;
  int times_to_lose_on_end_query_;
};
SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
    LayerTreeHostContextTestLostContextWhileUpdatingResources);
class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
 public:
  LayerTreeHostContextTestLayersNotified()
      : LayerTreeHostContextTest(), num_commits_(0) {}
  virtual void SetupTree() OVERRIDE {
    root_ = FakeContentLayer::Create(&client_);
    child_ = FakeContentLayer::Create(&client_);
    grandchild_ = FakeContentLayer::Create(&client_);
    root_->AddChild(child_);
    child_->AddChild(grandchild_);
    layer_tree_host()->SetRootLayer(root_);
    LayerTreeHostContextTest::SetupTree();
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
    FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
        host_impl->active_tree()->root_layer());
    FakeContentLayerImpl* child =
        static_cast<FakeContentLayerImpl*>(root->children()[0]);
    FakeContentLayerImpl* grandchild =
        static_cast<FakeContentLayerImpl*>(child->children()[0]);
    ++num_commits_;
    switch (num_commits_) {
      case 1:
        EXPECT_EQ(0u, root->lost_output_surface_count());
        EXPECT_EQ(0u, child->lost_output_surface_count());
        EXPECT_EQ(0u, grandchild->lost_output_surface_count());
        
        LoseContext();
        times_to_fail_create_ = 1;
        break;
      case 2:
        EXPECT_GE(1u, root->lost_output_surface_count());
        EXPECT_GE(1u, child->lost_output_surface_count());
        EXPECT_GE(1u, grandchild->lost_output_surface_count());
        EndTest();
        break;
      default:
        NOTREACHED();
    }
  }
  virtual void AfterTest() OVERRIDE {}
 private:
  int num_commits_;
  FakeContentLayerClient client_;
  scoped_refptr<FakeContentLayer> root_;
  scoped_refptr<FakeContentLayer> child_;
  scoped_refptr<FakeContentLayer> grandchild_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
class LayerTreeHostContextTestDontUseLostResources
    : public LayerTreeHostContextTest {
 public:
  LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
    context_should_support_io_surface_ = true;
    child_output_surface_ = FakeOutputSurface::Create3d();
    child_output_surface_->BindToClient(&output_surface_client_);
    shared_bitmap_manager_.reset(new TestSharedBitmapManager());
    child_resource_provider_ = ResourceProvider::Create(
        child_output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1);
  }
  static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
  virtual void SetupTree() OVERRIDE {
    gpu::gles2::GLES2Interface* gl =
        child_output_surface_->context_provider()->ContextGL();
    scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
    scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
    pass_for_quad->SetNew(
        
        RenderPass::Id(2, 1),
        gfx::Rect(0, 0, 10, 10),
        gfx::Rect(0, 0, 10, 10),
        gfx::Transform());
    scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
    pass->SetNew(RenderPass::Id(1, 1),
                 gfx::Rect(0, 0, 10, 10),
                 gfx::Rect(0, 0, 10, 10),
                 gfx::Transform());
    pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
                                   RenderPass::Id(2, 1));
    frame_data->render_pass_list.push_back(pass_for_quad.PassAs<RenderPass>());
    frame_data->render_pass_list.push_back(pass.PassAs<RenderPass>());
    delegated_resource_collection_ = new DelegatedFrameResourceCollection;
    delegated_frame_provider_ = new DelegatedFrameProvider(
        delegated_resource_collection_.get(), frame_data.Pass());
    ResourceProvider::ResourceId resource =
        child_resource_provider_->CreateResource(
            gfx::Size(4, 4),
            GL_CLAMP_TO_EDGE,
            ResourceProvider::TextureUsageAny,
            RGBA_8888);
    ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
                                             resource);
    gpu::Mailbox mailbox;
    gl->GenMailboxCHROMIUM(mailbox.name);
    GLuint sync_point = gl->InsertSyncPointCHROMIUM();
    scoped_refptr<Layer> root = Layer::Create();
    root->SetBounds(gfx::Size(10, 10));
    root->SetAnchorPoint(gfx::PointF());
    root->SetIsDrawable(true);
    scoped_refptr<FakeDelegatedRendererLayer> delegated =
        FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get());
    delegated->SetBounds(gfx::Size(10, 10));
    delegated->SetAnchorPoint(gfx::PointF());
    delegated->SetIsDrawable(true);
    root->AddChild(delegated);
    scoped_refptr<ContentLayer> content = ContentLayer::Create(&client_);
    content->SetBounds(gfx::Size(10, 10));
    content->SetAnchorPoint(gfx::PointF());
    content->SetIsDrawable(true);
    root->AddChild(content);
    scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL);
    texture->SetBounds(gfx::Size(10, 10));
    texture->SetAnchorPoint(gfx::PointF());
    texture->SetIsDrawable(true);
    texture->SetTextureMailbox(
        TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
        SingleReleaseCallback::Create(
            base::Bind(&LayerTreeHostContextTestDontUseLostResources::
                            EmptyReleaseCallback)));
    root->AddChild(texture);
    scoped_refptr<ContentLayer> mask = ContentLayer::Create(&client_);
    mask->SetBounds(gfx::Size(10, 10));
    mask->SetAnchorPoint(gfx::PointF());
    scoped_refptr<ContentLayer> content_with_mask =
        ContentLayer::Create(&client_);
    content_with_mask->SetBounds(gfx::Size(10, 10));
    content_with_mask->SetAnchorPoint(gfx::PointF());
    content_with_mask->SetIsDrawable(true);
    content_with_mask->SetMaskLayer(mask.get());
    root->AddChild(content_with_mask);
    scoped_refptr<VideoLayer> video_color =
        VideoLayer::Create(&color_frame_provider_);
    video_color->SetBounds(gfx::Size(10, 10));
    video_color->SetAnchorPoint(gfx::PointF());
    video_color->SetIsDrawable(true);
    root->AddChild(video_color);
    scoped_refptr<VideoLayer> video_hw =
        VideoLayer::Create(&hw_frame_provider_);
    video_hw->SetBounds(gfx::Size(10, 10));
    video_hw->SetAnchorPoint(gfx::PointF());
    video_hw->SetIsDrawable(true);
    root->AddChild(video_hw);
    scoped_refptr<VideoLayer> video_scaled_hw =
        VideoLayer::Create(&scaled_hw_frame_provider_);
    video_scaled_hw->SetBounds(gfx::Size(10, 10));
    video_scaled_hw->SetAnchorPoint(gfx::PointF());
    video_scaled_hw->SetIsDrawable(true);
    root->AddChild(video_scaled_hw);
    color_video_frame_ = VideoFrame::CreateColorFrame(
        gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
    hw_video_frame_ =
        VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
                                          mailbox, GL_TEXTURE_2D, sync_point)),
                                      media::VideoFrame::ReleaseMailboxCB(),
                                      gfx::Size(4, 4),
                                      gfx::Rect(0, 0, 4, 4),
                                      gfx::Size(4, 4),
                                      base::TimeDelta(),
                                      VideoFrame::ReadPixelsCB());
    scaled_hw_video_frame_ =
        VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
                                          mailbox, GL_TEXTURE_2D, sync_point)),
                                      media::VideoFrame::ReleaseMailboxCB(),
                                      gfx::Size(4, 4),
                                      gfx::Rect(0, 0, 3, 2),
                                      gfx::Size(4, 4),
                                      base::TimeDelta(),
                                      VideoFrame::ReadPixelsCB());
    color_frame_provider_.set_frame(color_video_frame_);
    hw_frame_provider_.set_frame(hw_video_frame_);
    scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
    if (!delegating_renderer()) {
      
      scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
      io_surface->SetBounds(gfx::Size(10, 10));
      io_surface->SetAnchorPoint(gfx::PointF());
      io_surface->SetIsDrawable(true);
      io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
      root->AddChild(io_surface);
    }
    
    LayerTreeDebugState debug_state;
    debug_state.show_property_changed_rects = true;
    layer_tree_host()->SetDebugState(debug_state);
    scoped_refptr<PaintedScrollbarLayer> scrollbar =
        PaintedScrollbarLayer::Create(
            scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content->id());
    scrollbar->SetBounds(gfx::Size(10, 10));
    scrollbar->SetAnchorPoint(gfx::PointF());
    scrollbar->SetIsDrawable(true);
    root->AddChild(scrollbar);
    layer_tree_host()->SetRootLayer(root);
    LayerTreeHostContextTest::SetupTree();
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
    if (host_impl->active_tree()->source_frame_number() == 3) {
      
      
      
      hw_frame_provider_.set_frame(NULL);
      scaled_hw_frame_provider_.set_frame(NULL);
    }
  }
  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
      LayerTreeHostImpl* host_impl,
      LayerTreeHostImpl::FrameData* frame,
      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
    if (host_impl->active_tree()->source_frame_number() == 2) {
      
      
      context3d_->set_times_bind_texture_succeeds(0);
    }
    return draw_result;
  }
  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
      OVERRIDE {
    
    
    if (layer_tree_host()->source_frame_number() > 0) {
      
      lost_context_ = true;
    }
    return LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
  }
  virtual void DidCommitAndDrawFrame() OVERRIDE {
    ASSERT_TRUE(layer_tree_host()->hud_layer());
    
    if (layer_tree_host()->source_frame_number() < 5) {
      layer_tree_host()->root_layer()->SetNeedsDisplay();
      layer_tree_host()->SetNeedsCommit();
    } else {
      EndTest();
    }
  }
  virtual void AfterTest() OVERRIDE { EXPECT_TRUE(lost_context_); }
 private:
  FakeContentLayerClient client_;
  bool lost_context_;
  FakeOutputSurfaceClient output_surface_client_;
  scoped_ptr<FakeOutputSurface> child_output_surface_;
  scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
  scoped_ptr<ResourceProvider> child_resource_provider_;
  scoped_refptr<DelegatedFrameResourceCollection>
      delegated_resource_collection_;
  scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
  scoped_refptr<VideoFrame> color_video_frame_;
  scoped_refptr<VideoFrame> hw_video_frame_;
  scoped_refptr<VideoFrame> scaled_hw_video_frame_;
  FakeVideoFrameProvider color_frame_provider_;
  FakeVideoFrameProvider hw_frame_provider_;
  FakeVideoFrameProvider scaled_hw_frame_provider_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit
    : public LayerTreeHostContextTest {
 public:
  virtual void BeginTest() OVERRIDE {
    
    
    ASSERT_TRUE(layer_tree_host()->output_surface_lost());
    times_output_surface_created_ = 0;
    
    
    
    PostSetNeedsCommitToMainThread();
    char pixels[4];
    bool result =
        layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(1, 1));
    EXPECT_EQ(!delegating_renderer(), result);
    EXPECT_EQ(1, times_output_surface_created_);
  }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    EXPECT_TRUE(succeeded);
    ++times_output_surface_created_;
  }
  virtual void DidCommitAndDrawFrame() OVERRIDE { EndTest(); }
  virtual void AfterTest() OVERRIDE {
    
    
    EXPECT_EQ(1, times_output_surface_created_);
  }
  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
      LayerTreeHostImpl* host_impl,
      LayerTreeHostImpl::FrameData* frame_data,
      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
    EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
    EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
    return draw_result;
  }
  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    
    
    
    EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
    EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
  }
  virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
                                   bool result) OVERRIDE {
    
    EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 1);
    EndTest();
  }
 private:
  int times_output_surface_created_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit);
class LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw
    : public LayerTreeHostContextTest {
 protected:
  static const int kFirstOutputSurfaceInitSourceFrameNumber = 0;
  static const int kReadbackSourceFrameNumber = 1;
  static const int kReadbackReplacementSourceFrameNumber = 2;
  static const int kSecondOutputSurfaceInitSourceFrameNumber = 3;
  LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw()
      : did_react_to_first_commit_(false) {}
  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
    
    settings->timeout_and_draw_when_animation_checkerboards = true;
    settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
      LayerTreeHostImpl* host_impl,
      LayerTreeHostImpl::FrameData* frame_data,
      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
    int sfn = host_impl->active_tree()->source_frame_number();
    EXPECT_TRUE(sfn == kFirstOutputSurfaceInitSourceFrameNumber ||
                sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
                sfn == kReadbackSourceFrameNumber)
        << sfn;
    
    
    
    if (sfn == kFirstOutputSurfaceInitSourceFrameNumber &&
        !did_react_to_first_commit_) {
      did_react_to_first_commit_ = true;
      PostReadbackToMainThread();
      LoseContext();
    }
    return DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
  }
  virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
                                           bool success) OVERRIDE {
    
    int sfn = host_impl->active_tree()->source_frame_number();
    EXPECT_TRUE(sfn == -1 || sfn == kReadbackReplacementSourceFrameNumber)
        << sfn;
  }
  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    
    
    
    int sfn = host_impl->active_tree()->source_frame_number();
    EXPECT_TRUE(sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
                sfn == kReadbackSourceFrameNumber)
        << sfn;
  }
  virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
                                   bool result) OVERRIDE {
    
    
    int sfn = host_impl->active_tree()->source_frame_number();
    EXPECT_TRUE(sfn == kSecondOutputSurfaceInitSourceFrameNumber) << sfn;
    EndTest();
  }
  virtual void AfterTest() OVERRIDE {}
  int did_react_to_first_commit_;
};
MULTI_THREAD_TEST_F(
    LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw);
class LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit
    : public LayerTreeHostContextTest {
 protected:
  static const int kFirstOutputSurfaceInitSourceFrameNumber = 0;
  static const int kReadbackSourceFrameNumber = 1;
  static const int kForcedDrawCommitSourceFrameNumber = 2;
  static const int kSecondOutputSurfaceInitSourceFrameNumber = 2;
  LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit()
      : did_lose_context_(false) {}
  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
    
    settings->timeout_and_draw_when_animation_checkerboards = true;
    settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
      LayerTreeHostImpl* host_impl,
      LayerTreeHostImpl::FrameData* frame_data,
      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
    int sfn = host_impl->active_tree()->source_frame_number();
    EXPECT_TRUE(sfn == kFirstOutputSurfaceInitSourceFrameNumber ||
                sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
                sfn == kReadbackSourceFrameNumber)
        << sfn;
    
    
    
    if (sfn == kFirstOutputSurfaceInitSourceFrameNumber && !did_lose_context_) {
      did_lose_context_ = true;
      LoseContext();
    }
    
    return DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
  }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    EXPECT_TRUE(succeeded);
    if (layer_tree_host()->source_frame_number() > 0) {
      
      
      char pixels[4];
      layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
    }
  }
  virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
                                           bool success) OVERRIDE {
    
    int sfn = host_impl->active_tree()->source_frame_number();
    EXPECT_TRUE(sfn == -1 || sfn == kFirstOutputSurfaceInitSourceFrameNumber)
        << sfn;
  }
  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
    
    
    
    int sfn = host_impl->active_tree()->source_frame_number();
    EXPECT_TRUE(sfn == kForcedDrawCommitSourceFrameNumber ||
                sfn == kReadbackSourceFrameNumber)
        << sfn;
  }
  virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
                                   bool result) OVERRIDE {
    
    
    int sfn = host_impl->active_tree()->source_frame_number();
    EXPECT_TRUE(sfn == kForcedDrawCommitSourceFrameNumber) << sfn;
    EndTest();
  }
  virtual void AfterTest() OVERRIDE {}
  int did_lose_context_;
};
MULTI_THREAD_TEST_F(
    LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit);
class ImplSidePaintingLayerTreeHostContextTest
    : public LayerTreeHostContextTest {
 public:
  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
    settings->impl_side_painting = true;
  }
};
class LayerTreeHostContextTestImplSidePainting
    : public ImplSidePaintingLayerTreeHostContextTest {
 public:
  virtual void SetupTree() OVERRIDE {
    scoped_refptr<Layer> root = Layer::Create();
    root->SetBounds(gfx::Size(10, 10));
    root->SetAnchorPoint(gfx::PointF());
    root->SetIsDrawable(true);
    scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
    picture->SetBounds(gfx::Size(10, 10));
    picture->SetAnchorPoint(gfx::PointF());
    picture->SetIsDrawable(true);
    root->AddChild(picture);
    layer_tree_host()->SetRootLayer(root);
    LayerTreeHostContextTest::SetupTree();
  }
  virtual void BeginTest() OVERRIDE {
    times_to_lose_during_commit_ = 1;
    PostSetNeedsCommitToMainThread();
  }
  virtual void AfterTest() OVERRIDE {}
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    EXPECT_TRUE(succeeded);
    EndTest();
  }
 private:
  FakeContentLayerClient client_;
};
MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
 public:
  ScrollbarLayerLostContext() : commits_(0) {}
  virtual void BeginTest() OVERRIDE {
    scoped_refptr<Layer> scroll_layer = Layer::Create();
    scrollbar_layer_ =
        FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id());
    scrollbar_layer_->SetBounds(gfx::Size(10, 100));
    layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
    layer_tree_host()->root_layer()->AddChild(scroll_layer);
    PostSetNeedsCommitToMainThread();
  }
  virtual void AfterTest() OVERRIDE {}
  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
    ++commits_;
    switch (commits_) {
      case 1:
        
        
        EXPECT_EQ(1, scrollbar_layer_->update_count());
        LoseContext();
        break;
      case 2:
        
        
        EXPECT_EQ(2, scrollbar_layer_->update_count());
        EndTest();
        break;
      case 3:
        
        
        if (HasImplThread())
          NOTREACHED();
        break;
      default:
        NOTREACHED();
    }
  }
 private:
  int commits_;
  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
class UIResourceLostTest : public LayerTreeHostContextTest {
 public:
  UIResourceLostTest() : time_step_(0) {}
  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
    settings->texture_id_allocation_chunk_size = 1;
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual void AfterTest() OVERRIDE {}
  
  
  
  
  
  
  
  virtual void StepCompleteOnMainThread(int time_step) = 0;
  
  
  
  void PostStepCompleteToMainThread() {
    proxy()->MainThreadTaskRunner()->PostTask(
        FROM_HERE,
        base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
                   base::Unretained(this),
                   time_step_));
  }
  void PostLoseContextToImplThread() {
    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
    base::SingleThreadTaskRunner* task_runner =
        HasImplThread() ? ImplThreadTaskRunner()
                        : base::MessageLoopProxy::current();
    task_runner->PostTask(FROM_HERE,
                          base::Bind(&LayerTreeHostContextTest::LoseContext,
                                     base::Unretained(this)));
  }
 protected:
  int time_step_;
  scoped_ptr<FakeScopedUIResource> ui_resource_;
 private:
  void StepCompleteOnMainThreadInternal(int step) {
    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
    StepCompleteOnMainThread(step);
  }
};
class UIResourceLostTestSimple : public UIResourceLostTest {
 public:
  
  
  virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    if (!layer_tree_host()->settings().impl_side_painting) {
      StepCompleteOnImplThread(impl);
      PostStepCompleteToMainThread();
      ++time_step_;
    }
  }
  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    if (layer_tree_host()->settings().impl_side_painting) {
      StepCompleteOnImplThread(impl);
      PostStepCompleteToMainThread();
      ++time_step_;
    }
  }
};
class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
 public:
  virtual void StepCompleteOnMainThread(int step) OVERRIDE {
    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
    switch (step) {
      case 0:
        ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
        
        EXPECT_NE(0, ui_resource_->id());
        PostSetNeedsCommitToMainThread();
        break;
      case 4:
        
        ui_resource_.reset();
        EndTest();
        break;
      case 5:
        
        
        if (HasImplThread())
          NOTREACHED();
        break;
      case 6:
        NOTREACHED();
    }
  }
  virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
    switch (time_step_) {
      case 1:
        
        EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
        PostSetNeedsCommitToMainThread();
        break;
      case 2:
        LoseContext();
        break;
      case 3:
        
        
        EXPECT_EQ(1, ui_resource_->lost_resource_count);
        
        
        EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
        PostSetNeedsCommitToMainThread();
        break;
    }
  }
};
SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
 public:
  UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
  virtual void StepCompleteOnMainThread(int step) OVERRIDE {
    switch (step) {
      case 0:
        ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
        
        PostLoseContextToImplThread();
        break;
      case 2:
        
        
        test_id0_ = ui_resource_->id();
        
        ui_resource_.reset();
        
        ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
        test_id1_ = ui_resource_->id();
        
        EXPECT_NE(test_id0_, test_id1_);
        
        PostLoseContextToImplThread();
        break;
      case 3:
        
        ui_resource_.reset();
        PostSetNeedsCommitToMainThread();
        break;
      case 4:
        
        ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
        test_id0_ = ui_resource_->id();
        
        EXPECT_NE(0, test_id0_);
        
        
        
        layer_tree_host()->DeleteUIResource(test_id0_);
        
        PostLoseContextToImplThread();
        break;
      case 5:
        
        ui_resource_.reset();
        EndTest();
        break;
      case 6:
        
        
        if (HasImplThread())
          NOTREACHED();
        break;
      case 8:
        NOTREACHED();
    }
  }
  virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
    switch (time_step_) {
      case 1:
        
        
        
        
        EXPECT_EQ(1, ui_resource_->resource_create_count);
        EXPECT_EQ(0, ui_resource_->lost_resource_count);
        
        PostSetNeedsCommitToMainThread();
        break;
      case 3:
        
        
        EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
        if (HasImplThread()) {
          
          EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
        } else {
          
          
          
          EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id1_));
        }
        
        
        EXPECT_EQ(2, ui_resource_->resource_create_count);
        EXPECT_EQ(1, ui_resource_->lost_resource_count);
        break;
      case 5:
        
        
        EXPECT_EQ(1, ui_resource_->resource_create_count);
        
        EXPECT_EQ(0, ui_resource_->lost_resource_count);
        
        EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
        break;
    }
  }
 private:
  UIResourceId test_id0_;
  UIResourceId test_id1_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
  virtual void StepCompleteOnMainThread(int step) OVERRIDE {
    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
    switch (step) {
      case 0:
        ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
        PostSetNeedsCommitToMainThread();
        break;
      case 3:
        test_id_ = ui_resource_->id();
        ui_resource_.reset();
        PostSetNeedsCommitToMainThread();
        break;
      case 5:
        
        ui_resource_.reset();
        EndTest();
        break;
      case 6:
        
        NOTREACHED();
    }
  }
  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
    switch (time_step_) {
      case 2:
        PostSetNeedsCommitToMainThread();
        break;
      case 4:
        PostSetNeedsCommitToMainThread();
        break;
    }
  }
  virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    switch (time_step_) {
      case 1:
        
        EXPECT_EQ(1, ui_resource_->resource_create_count);
        
        EXPECT_EQ(0, ui_resource_->lost_resource_count);
        
        EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
        LoseContext();
        break;
      case 3:
        LoseContext();
        break;
    }
  }
  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
    switch (time_step_) {
      case 1:
        
        EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
        break;
      case 2:
        
        EXPECT_EQ(1, ui_resource_->lost_resource_count);
        break;
      case 4:
        
        
        EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
        break;
    }
    PostStepCompleteToMainThread();
    ++time_step_;
  }
 private:
  UIResourceId test_id_;
};
TEST_F(UIResourceLostBeforeActivateTree,
       RunMultiThread_DirectRenderer_ImplSidePaint) {
  RunTest(true, false, true);
}
TEST_F(UIResourceLostBeforeActivateTree,
       RunMultiThread_DelegatingRenderer_ImplSidePaint) {
  RunTest(true, true, true);
}
class UIResourceLostEviction : public UIResourceLostTestSimple {
 public:
  virtual void StepCompleteOnMainThread(int step) OVERRIDE {
    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
    switch (step) {
      case 0:
        ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
        EXPECT_NE(0, ui_resource_->id());
        PostSetNeedsCommitToMainThread();
        break;
      case 2:
        
        PostSetVisibleToMainThread(false);
        break;
      case 3:
        
        ui_resource_.reset();
        EndTest();
        break;
      case 4:
        NOTREACHED();
    }
  }
  virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl,
                                       bool visible) OVERRIDE {
    TestWebGraphicsContext3D* context = TestContext();
    if (!visible) {
      
      ASSERT_EQ(0u, context->NumTextures());
      EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
      EXPECT_EQ(2, ui_resource_->resource_create_count);
      EXPECT_EQ(1, ui_resource_->lost_resource_count);
      
      
      EXPECT_FALSE(impl->CanDraw());
      
      PostSetVisibleToMainThread(true);
    }
  }
  virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
    TestWebGraphicsContext3D* context = TestContext();
    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
    switch (time_step_) {
      case 1:
        
        ASSERT_EQ(1u, context->NumTextures());
        EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
        EXPECT_EQ(1, ui_resource_->resource_create_count);
        EXPECT_EQ(0, ui_resource_->lost_resource_count);
        EXPECT_TRUE(impl->CanDraw());
        
        impl->EvictAllUIResources();
        ASSERT_EQ(0u, context->NumTextures());
        EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
        EXPECT_EQ(1, ui_resource_->resource_create_count);
        EXPECT_EQ(0, ui_resource_->lost_resource_count);
        EXPECT_FALSE(impl->CanDraw());
        break;
      case 2:
        
        ASSERT_EQ(1u, context->NumTextures());
        EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
        EXPECT_EQ(2, ui_resource_->resource_create_count);
        EXPECT_EQ(1, ui_resource_->lost_resource_count);
        EXPECT_TRUE(impl->CanDraw());
        break;
      case 3:
        
        
        ASSERT_EQ(1u, context->NumTextures());
        EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
        EXPECT_EQ(3, ui_resource_->resource_create_count);
        EXPECT_EQ(2, ui_resource_->lost_resource_count);
        EXPECT_TRUE(impl->CanDraw());
        break;
    }
  }
};
SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
class LayerTreeHostContextTestSurfaceCreateCallback
    : public LayerTreeHostContextTest {
 public:
  LayerTreeHostContextTestSurfaceCreateCallback()
      : LayerTreeHostContextTest(),
        layer_(FakeContentLayer::Create(&client_)) {}
  virtual void SetupTree() OVERRIDE {
    layer_->SetBounds(gfx::Size(10, 20));
    layer_tree_host()->SetRootLayer(layer_);
    LayerTreeHostContextTest::SetupTree();
  }
  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
  virtual void DidCommit() OVERRIDE {
    switch (layer_tree_host()->source_frame_number()) {
      case 1:
        EXPECT_EQ(1u, layer_->output_surface_created_count());
        layer_tree_host()->SetNeedsCommit();
        break;
      case 2:
        EXPECT_EQ(1u, layer_->output_surface_created_count());
        layer_tree_host()->SetNeedsCommit();
        break;
      case 3:
        EXPECT_EQ(1u, layer_->output_surface_created_count());
        break;
      case 4:
        EXPECT_EQ(2u, layer_->output_surface_created_count());
        layer_tree_host()->SetNeedsCommit();
        break;
    }
  }
  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
    switch (LastCommittedSourceFrameNumber(impl)) {
      case 0:
        break;
      case 1:
        break;
      case 2:
        LoseContext();
        break;
      case 3:
        EndTest();
        break;
    }
  }
  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
    EXPECT_TRUE(succeeded);
  }
  virtual void AfterTest() OVERRIDE {}
 protected:
  FakeContentLayerClient client_;
  scoped_refptr<FakeContentLayer> layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
}  
}