| Index: cc/trees/layer_tree_host_unittest_picture.cc
 | 
| diff --git a/cc/trees/layer_tree_host_unittest_picture.cc b/cc/trees/layer_tree_host_unittest_picture.cc
 | 
| index 159200a2df13eaad8df6481ce1b2bd2889f6dcba..5ce47cd42862e834c4434ac32b8067696fb82a08 100644
 | 
| --- a/cc/trees/layer_tree_host_unittest_picture.cc
 | 
| +++ b/cc/trees/layer_tree_host_unittest_picture.cc
 | 
| @@ -135,7 +135,8 @@ class LayerTreeHostPictureTestTwinLayer
 | 
|    int activates_;
 | 
|  };
 | 
|  
 | 
| -SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestTwinLayer);
 | 
| +// There is no pending layers in single thread mode.
 | 
| +MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestTwinLayer);
 | 
|  
 | 
|  class LayerTreeHostPictureTestResizeViewportWithGpuRaster
 | 
|      : public LayerTreeHostPictureTest {
 | 
| @@ -158,7 +159,7 @@ class LayerTreeHostPictureTestResizeViewportWithGpuRaster
 | 
|  
 | 
|    void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 | 
|  
 | 
| -  void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
 | 
| +  void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
 | 
|      LayerImpl* child = impl->sync_tree()->root_layer()->children()[0];
 | 
|      FakePictureLayerImpl* picture_impl =
 | 
|          static_cast<FakePictureLayerImpl*>(child);
 | 
| @@ -324,8 +325,247 @@ class LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree
 | 
|    scoped_refptr<FakePictureLayer> picture_;
 | 
|  };
 | 
|  
 | 
| -SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
 | 
| +// Multi-thread only since there is no recycle tree in single thread.
 | 
| +MULTI_THREAD_IMPL_TEST_F(
 | 
|      LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree);
 | 
|  
 | 
| +class LayerTreeHostPictureTestRSLLMembership : public LayerTreeHostPictureTest {
 | 
| +  void SetupTree() override {
 | 
| +    scoped_refptr<Layer> root = Layer::Create();
 | 
| +    root->SetBounds(gfx::Size(100, 100));
 | 
| +
 | 
| +    child_ = Layer::Create();
 | 
| +    root->AddChild(child_);
 | 
| +
 | 
| +    // Don't be solid color so the layer has tilings/tiles.
 | 
| +    client_.set_fill_with_nonsolid_color(true);
 | 
| +    picture_ = FakePictureLayer::Create(&client_);
 | 
| +    picture_->SetBounds(gfx::Size(100, 100));
 | 
| +    child_->AddChild(picture_);
 | 
| +
 | 
| +    layer_tree_host()->SetRootLayer(root);
 | 
| +    LayerTreeHostPictureTest::SetupTree();
 | 
| +  }
 | 
| +
 | 
| +  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 | 
| +
 | 
| +  void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
 | 
| +    LayerImpl* root = impl->sync_tree()->root_layer();
 | 
| +    LayerImpl* child = root->children()[0];
 | 
| +    LayerImpl* gchild = child->children()[0];
 | 
| +    FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
 | 
| +
 | 
| +    switch (impl->sync_tree()->source_frame_number()) {
 | 
| +      case 0:
 | 
| +        // On 1st commit the layer has tilings.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +        break;
 | 
| +      case 1:
 | 
| +        // On 2nd commit, the layer is transparent, but its tilings are left
 | 
| +        // there.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +        break;
 | 
| +      case 2:
 | 
| +        // On 3rd commit, the layer is visible again, so has tilings.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
 | 
| +    LayerImpl* root = impl->active_tree()->root_layer();
 | 
| +    LayerImpl* child = root->children()[0];
 | 
| +    LayerImpl* gchild = child->children()[0];
 | 
| +    FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
 | 
| +
 | 
| +    switch (impl->active_tree()->source_frame_number()) {
 | 
| +      case 0:
 | 
| +        // On 1st commit the layer has tilings.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +        break;
 | 
| +      case 1:
 | 
| +        // On 2nd commit, the layer is transparent, but its tilings are left
 | 
| +        // there.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +        break;
 | 
| +      case 2:
 | 
| +        // On 3rd commit, the layer is visible again, so has tilings.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +        EndTest();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void DidCommit() override {
 | 
| +    switch (layer_tree_host()->source_frame_number()) {
 | 
| +      case 1:
 | 
| +        // For the 2nd commit, change opacity to 0 so that the layer will not be
 | 
| +        // part of the visible frame.
 | 
| +        child_->SetOpacity(0.f);
 | 
| +        break;
 | 
| +      case 2:
 | 
| +        // For the 3rd commit, change opacity to 1 so that the layer will again
 | 
| +        // be part of the visible frame.
 | 
| +        child_->SetOpacity(1.f);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void AfterTest() override {}
 | 
| +
 | 
| +  FakeContentLayerClient client_;
 | 
| +  scoped_refptr<Layer> child_;
 | 
| +  scoped_refptr<FakePictureLayer> picture_;
 | 
| +};
 | 
| +
 | 
| +SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestRSLLMembership);
 | 
| +
 | 
| +class LayerTreeHostPictureTestRSLLMembershipWithScale
 | 
| +    : public LayerTreeHostPictureTest {
 | 
| +  void SetupTree() override {
 | 
| +    scoped_refptr<Layer> root = Layer::Create();
 | 
| +    root->SetBounds(gfx::Size(100, 100));
 | 
| +
 | 
| +    pinch_ = Layer::Create();
 | 
| +    pinch_->SetBounds(gfx::Size(500, 500));
 | 
| +    pinch_->SetScrollClipLayerId(root->id());
 | 
| +    pinch_->SetIsContainerForFixedPositionLayers(true);
 | 
| +    root->AddChild(pinch_);
 | 
| +
 | 
| +    // Don't be solid color so the layer has tilings/tiles.
 | 
| +    client_.set_fill_with_nonsolid_color(true);
 | 
| +    picture_ = FakePictureLayer::Create(&client_);
 | 
| +    picture_->SetBounds(gfx::Size(100, 100));
 | 
| +    pinch_->AddChild(picture_);
 | 
| +
 | 
| +    layer_tree_host()->RegisterViewportLayers(NULL, root, pinch_, pinch_);
 | 
| +    layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
 | 
| +    layer_tree_host()->SetRootLayer(root);
 | 
| +    LayerTreeHostPictureTest::SetupTree();
 | 
| +  }
 | 
| +
 | 
| +  void InitializeSettings(LayerTreeSettings* settings) override {
 | 
| +    settings->layer_transforms_should_scale_layer_contents = true;
 | 
| +  }
 | 
| +
 | 
| +  void BeginTest() override {
 | 
| +    frame_ = 0;
 | 
| +    draws_in_frame_ = 0;
 | 
| +    last_frame_drawn_ = -1;
 | 
| +    PostSetNeedsCommitToMainThread();
 | 
| +  }
 | 
| +
 | 
| +  void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
 | 
| +    LayerImpl* root = impl->sync_tree()->root_layer();
 | 
| +    LayerImpl* pinch = root->children()[0];
 | 
| +    LayerImpl* gchild = pinch->children()[0];
 | 
| +    FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
 | 
| +
 | 
| +    switch (frame_) {
 | 
| +      case 0:
 | 
| +        // On 1st commit the layer has tilings.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +        break;
 | 
| +      case 1:
 | 
| +        // On 2nd commit, the layer is transparent, so does not have tilings.
 | 
| +        EXPECT_EQ(0u, picture->tilings()->num_tilings());
 | 
| +        break;
 | 
| +      case 2:
 | 
| +        // On 3rd commit, the layer is visible again, so has tilings.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
 | 
| +    LayerImpl* root = impl->active_tree()->root_layer();
 | 
| +    LayerImpl* pinch = root->children()[0];
 | 
| +    LayerImpl* gchild = pinch->children()[0];
 | 
| +    FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
 | 
| +
 | 
| +    if (frame_ != last_frame_drawn_)
 | 
| +      draws_in_frame_ = 0;
 | 
| +    ++draws_in_frame_;
 | 
| +    last_frame_drawn_ = frame_;
 | 
| +
 | 
| +    switch (frame_) {
 | 
| +      case 0:
 | 
| +        if (draws_in_frame_ == 1) {
 | 
| +          // On 1st commit the layer has tilings.
 | 
| +          EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +          EXPECT_EQ(1.f, picture->HighResTiling()->contents_scale());
 | 
| +
 | 
| +          // Pinch zoom in to change the scale on the active tree.
 | 
| +          impl->PinchGestureBegin();
 | 
| +          impl->PinchGestureUpdate(2.f, gfx::Point(1, 1));
 | 
| +          impl->PinchGestureEnd();
 | 
| +        } else if (picture->tilings()->num_tilings() == 1) {
 | 
| +          // If the pinch gesture caused a commit we could get here with a
 | 
| +          // pending tree.
 | 
| +          EXPECT_FALSE(impl->pending_tree());
 | 
| +          // The active layer now has only a 2.f scale tiling, which means the
 | 
| +          // recycled layer's tiling is destroyed.
 | 
| +          EXPECT_EQ(2.f, picture->HighResTiling()->contents_scale());
 | 
| +          EXPECT_EQ(0u, picture->GetRecycledTwinLayer()
 | 
| +                            ->picture_layer_tiling_set()
 | 
| +                            ->num_tilings());
 | 
| +
 | 
| +          ++frame_;
 | 
| +          MainThreadTaskRunner()->PostTask(
 | 
| +              FROM_HERE,
 | 
| +              base::Bind(
 | 
| +                  &LayerTreeHostPictureTestRSLLMembershipWithScale::NextStep,
 | 
| +                  base::Unretained(this)));
 | 
| +        }
 | 
| +        break;
 | 
| +      case 1:
 | 
| +        EXPECT_EQ(1, draws_in_frame_);
 | 
| +        // On 2nd commit, the layer is transparent, so does not create
 | 
| +        // tilings. Since the 1.f tiling was destroyed in the recycle tree, it
 | 
| +        // has no tilings left. This is propogated to the active tree.
 | 
| +        EXPECT_EQ(0u, picture->picture_layer_tiling_set()->num_tilings());
 | 
| +        EXPECT_EQ(0u, picture->GetRecycledTwinLayer()
 | 
| +                          ->picture_layer_tiling_set()
 | 
| +                          ->num_tilings());
 | 
| +        ++frame_;
 | 
| +        MainThreadTaskRunner()->PostTask(
 | 
| +            FROM_HERE,
 | 
| +            base::Bind(
 | 
| +                &LayerTreeHostPictureTestRSLLMembershipWithScale::NextStep,
 | 
| +                base::Unretained(this)));
 | 
| +        break;
 | 
| +      case 2:
 | 
| +        EXPECT_EQ(1, draws_in_frame_);
 | 
| +        // On 3rd commit, the layer is visible again, so has tilings.
 | 
| +        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
 | 
| +        EndTest();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void NextStep() {
 | 
| +    switch (frame_) {
 | 
| +      case 1:
 | 
| +        // For the 2nd commit, change opacity to 0 so that the layer will not be
 | 
| +        // part of the visible frame.
 | 
| +        pinch_->SetOpacity(0.f);
 | 
| +        break;
 | 
| +      case 2:
 | 
| +        // For the 3rd commit, change opacity to 1 so that the layer will again
 | 
| +        // be part of the visible frame.
 | 
| +        pinch_->SetOpacity(1.f);
 | 
| +        break;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void AfterTest() override {}
 | 
| +
 | 
| +  FakeContentLayerClient client_;
 | 
| +  scoped_refptr<Layer> pinch_;
 | 
| +  scoped_refptr<FakePictureLayer> picture_;
 | 
| +  int frame_;
 | 
| +  int draws_in_frame_;
 | 
| +  int last_frame_drawn_;
 | 
| +};
 | 
| +
 | 
| +// Multi-thread only because in single thread you can't pinch zoom on the
 | 
| +// compositor thread.
 | 
| +MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale);
 | 
| +
 | 
|  }  // namespace
 | 
|  }  // namespace cc
 | 
| 
 |