// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/layers/layer_impl.h"

#include <algorithm>

#include "base/memory/raw_ptr.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"
#include "cc/layers/solid_color_scrollbar_layer_impl.h"
#include "cc/paint/filter_operation.h"
#include "cc/paint/filter_operations.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/layer_tree_impl_test_base.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/test/geometry_util.h"

namespace cc {
namespace {

#define EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(code_to_test)           \
  root->layer_tree_impl()->ResetAllChangeTracking();                      \
  code_to_test;                                                           \
  EXPECT_FALSE(root->LayerPropertyChanged());                             \
  EXPECT_FALSE(child->LayerPropertyChanged());                            \
  EXPECT_FALSE(grand_child->LayerPropertyChanged());

#define EXECUTE_AND_VERIFY_SUBTREE_CHANGED(code_to_test)             \
  root->layer_tree_impl()->ResetAllChangeTracking();                 \
  code_to_test;                                                      \
  EXPECT_TRUE(root->LayerPropertyChanged());                         \
  EXPECT_TRUE(root->LayerPropertyChangedFromPropertyTrees());        \
  EXPECT_FALSE(root->LayerPropertyChangedNotFromPropertyTrees());    \
  EXPECT_TRUE(child->LayerPropertyChanged());                        \
  EXPECT_TRUE(child->LayerPropertyChangedFromPropertyTrees());       \
  EXPECT_FALSE(child->LayerPropertyChangedNotFromPropertyTrees());   \
  EXPECT_TRUE(grand_child->LayerPropertyChanged());                  \
  EXPECT_TRUE(grand_child->LayerPropertyChangedFromPropertyTrees()); \
  EXPECT_FALSE(grand_child->LayerPropertyChangedNotFromPropertyTrees());

#define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(code_to_test)                \
  root->layer_tree_impl()->ResetAllChangeTracking();                       \
  root->layer_tree_impl()->property_trees()->set_full_tree_damaged(false); \
  code_to_test;                                                            \
  EXPECT_TRUE(root->LayerPropertyChanged());                               \
  EXPECT_FALSE(root->LayerPropertyChangedFromPropertyTrees());             \
  EXPECT_TRUE(root->LayerPropertyChangedNotFromPropertyTrees());           \
  EXPECT_FALSE(child->LayerPropertyChanged());                             \
  EXPECT_FALSE(grand_child->LayerPropertyChanged());

#define VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(code_to_test)                   \
  root->layer_tree_impl()->ResetAllChangeTracking();                        \
  host_impl()->ForcePrepareToDraw();                                        \
  EXPECT_FALSE(host_impl()->active_tree()->needs_update_draw_properties()); \
  code_to_test;                                                             \
  EXPECT_TRUE(host_impl()->active_tree()->needs_update_draw_properties());

#define VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(code_to_test)                \
  root->layer_tree_impl()->ResetAllChangeTracking();                        \
  host_impl()->ForcePrepareToDraw();                                        \
  EXPECT_FALSE(host_impl()->active_tree()->needs_update_draw_properties()); \
  code_to_test;                                                             \
  EXPECT_FALSE(host_impl()->active_tree()->needs_update_draw_properties());

class LayerImplTest : public LayerTreeImplTestBase, public ::testing::Test {
 public:
  using LayerTreeImplTestBase::LayerTreeImplTestBase;
};

TEST_F(LayerImplTest, VerifyPendingLayerChangesAreTrackedProperly) {
  //
  // This test checks that LayerPropertyChanged() has the correct behavior.
  //

  // The constructor on this will fake that we are on the correct thread.
  // Create a simple LayerImpl tree:
  host_impl()->CreatePendingTree();
  LayerImpl* root = EnsureRootLayerInPendingTree();
  CreateClipNode(root);
  root->layer_tree_impl()->ResetAllChangeTracking();

  LayerImpl* child = AddLayerInPendingTree<LayerImpl>();
  CopyProperties(root, child);
  LayerImpl* grand_child = AddLayerInPendingTree<LayerImpl>();
  CopyProperties(child, grand_child);

  UpdatePendingTreeDrawProperties();

  // Creating children is an internal operation and should not mark layers as
  // changed.
  EXPECT_FALSE(root->LayerPropertyChanged());
  EXPECT_FALSE(child->LayerPropertyChanged());
  EXPECT_FALSE(grand_child->LayerPropertyChanged());

  float arbitrary_number = 0.352f;
  gfx::Size arbitrary_size = gfx::Size(111, 222);
  gfx::Point arbitrary_point = gfx::Point(333, 444);

  gfx::Rect arbitrary_rect = gfx::Rect(arbitrary_point, arbitrary_size);
  SkColor arbitrary_color = SkColorSetRGB(10, 20, 30);
  gfx::Transform arbitrary_transform;
  arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f);
  FilterOperations arbitrary_filters;
  arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f));

  // These properties are internal, and should not be considered "change" when
  // they are used.
  EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
      root->UnionUpdateRect(arbitrary_rect));
  EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetBounds(arbitrary_size));
  UpdatePendingTreeDrawProperties();

  // Changing these properties affects the entire subtree of layers.
  EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
      host_impl()->pending_tree()->SetFilterMutated(root->element_id(),
                                                    arbitrary_filters));
  EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
      host_impl()->pending_tree()->SetFilterMutated(root->element_id(),
                                                    FilterOperations()));
  EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
      host_impl()->pending_tree()->SetOpacityMutated(root->element_id(),
                                                     arbitrary_number));
  EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
      host_impl()->pending_tree()->SetTransformMutated(root->element_id(),
                                                       arbitrary_transform));

  // Changing these properties only affects the layer itself.
  EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetDrawsContent(true));
  EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(
      root->SetBackgroundColor(arbitrary_color));

  // Changing these properties does not cause the layer to be marked as changed
  // but does cause the layer to need to push properties.
  EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetElementId(ElementId(2)));

  // After setting all these properties already, setting to the exact same
  // values again should not cause any change.
  EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetContentsOpaque(true));
  EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetDrawsContent(true));
  EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetBounds(root->bounds()));
}

TEST_F(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
  LayerImpl* root = root_layer();
  LayerImpl* layer = AddLayer<LayerImpl>();
  layer->SetBounds(gfx::Size(100, 100));
  LayerImpl* layer2 = AddLayer<LayerImpl>();
  SetElementIdsForTesting();

  CopyProperties(root, layer);
  CreateTransformNode(layer);
  CreateScrollNode(layer, gfx::Size(1, 1));
  CopyProperties(root, layer2);

  DCHECK(host_impl()->CanDraw());
  UpdateActiveTreeDrawProperties();

  float arbitrary_number = 0.352f;
  gfx::Size arbitrary_size = gfx::Size(111, 222);
  gfx::Vector2d arbitrary_vector2d = gfx::Vector2d(111, 222);
  gfx::PointF arbitrary_scroll_offset(
      gfx::PointAtOffsetFromOrigin(arbitrary_vector2d));
  gfx::Size large_size = gfx::Size(1000, 1000);
  SkColor arbitrary_color = SkColorSetRGB(10, 20, 30);
  gfx::Transform arbitrary_transform;
  arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f);
  FilterOperations arbitrary_filters;
  arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f));

  // Set layer to draw content so that their draw property by property trees is
  // verified.
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetDrawsContent(true));
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer2->SetDrawsContent(true));

  // Create a render surface, because we must have a render surface if we have
  // filters.
  CreateEffectNode(layer).render_surface_reason = RenderSurfaceReason::kTest;
  UpdateActiveTreeDrawProperties();

  // Related filter functions.
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
      host_impl()->active_tree()->SetFilterMutated(root->element_id(),
                                                   arbitrary_filters));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
      host_impl()->active_tree()->SetFilterMutated(root->element_id(),
                                                   arbitrary_filters));
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
      host_impl()->active_tree()->SetFilterMutated(root->element_id(),
                                                   FilterOperations()));
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
      host_impl()->active_tree()->SetFilterMutated(root->element_id(),
                                                   arbitrary_filters));

  // Related scrolling functions.
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(large_size));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(large_size));
  host_impl()->active_tree()->set_needs_update_draw_properties();
  UpdateActiveTreeDrawProperties();

  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->ScrollBy(arbitrary_vector2d));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->ScrollBy(gfx::Vector2d()));
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
      layer->layer_tree_impl()->DidUpdateScrollOffset(layer->element_id()));
  layer->layer_tree_impl()
      ->property_trees()
      ->scroll_tree_mutable()
      .SetScrollOffsetDeltaForTesting(layer->element_id(), gfx::Vector2dF());
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
      layer->SetCurrentScrollOffset(arbitrary_scroll_offset));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
      layer->SetCurrentScrollOffset(arbitrary_scroll_offset));

  // Unrelated functions, always set to new values, always set needs update.
  host_impl()->active_tree()->set_needs_update_draw_properties();
  UpdateActiveTreeDrawProperties();
  CreateClipNode(layer);
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetContentsOpaque(true);
                                      layer->NoteLayerPropertyChanged());
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
      layer->SetBackgroundColor(arbitrary_color));
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
      host_impl()->active_tree()->SetOpacityMutated(layer->element_id(),
                                                    arbitrary_number));
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
      host_impl()->active_tree()->SetTransformMutated(layer->element_id(),
                                                      arbitrary_transform));
  VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(arbitrary_size);
                                      layer->NoteLayerPropertyChanged());

  // Unrelated functions, set to the same values, no needs update.
  GetEffectNode(layer)->filters = arbitrary_filters;
  UpdateActiveTreeDrawProperties();
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
      host_impl()->active_tree()->SetFilterMutated(layer->element_id(),
                                                   arbitrary_filters));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetContentsOpaque(true));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetDrawsContent(true));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
      layer->SetBackgroundColor(arbitrary_color));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(arbitrary_size));
  VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetElementId(ElementId(2)));
}

TEST_F(LayerImplTest, PerspectiveTransformHasReasonableScale) {
  LayerImpl* layer = root_layer();
  layer->SetBounds(gfx::Size(10, 10));
  layer->set_contributes_to_drawn_render_surface(true);

  // Ensure that we are close to the maximum scale for the matrix.
  {
    gfx::Transform transform;
    transform.Scale(10.2f, 15.1f);
    transform.ApplyPerspectiveDepth(10);
    transform.RotateAboutXAxis(15.0f);
    layer->draw_properties().screen_space_transform = transform;

    ASSERT_TRUE(layer->ScreenSpaceTransform().HasPerspective());
    EXPECT_EQ(gfx::Vector2dF(15.f, 15.f), layer->GetIdealContentsScale());
  }
  // Ensure that we don't fall below the device scale factor.
  {
    gfx::Transform transform;
    transform.Scale(0.1f, 0.2f);
    transform.ApplyPerspectiveDepth(10);
    transform.RotateAboutXAxis(15.0f);
    layer->draw_properties().screen_space_transform = transform;

    ASSERT_TRUE(layer->ScreenSpaceTransform().HasPerspective());
    EXPECT_EQ(gfx::Vector2dF(1.f, 1.f), layer->GetIdealContentsScale());
  }
  // Ensure that large scales don't end up extremely large.
  {
    gfx::Transform transform;
    transform.Scale(10000.1f, 10000.2f);
    transform.ApplyPerspectiveDepth(10);
    transform.RotateAboutXAxis(15.0f);
    layer->draw_properties().screen_space_transform = transform;

    ASSERT_TRUE(layer->ScreenSpaceTransform().HasPerspective());
    EXPECT_EQ(gfx::Vector2dF(127.f, 127.f), layer->GetIdealContentsScale());
  }
  // Test case from crbug.com/766021.
  {
    gfx::Transform transform(-0.9397f, -0.7019f, 0.2796f, 2383.4521f,   // row 1
                             -0.0038f, 0.0785f, 1.0613f, 1876.4553f,    // row 2
                             -0.0835f, 0.9081f, -0.4105f, -2208.3035f,  // row 3
                             0.0001f, -0.0008f, 0.0003f, 2.8435f);      // row 4
    layer->draw_properties().screen_space_transform = transform;

    ASSERT_TRUE(layer->ScreenSpaceTransform().HasPerspective());
    EXPECT_EQ(gfx::Vector2dF(1.f, 1.f), layer->GetIdealContentsScale());
  }
}

class LayerImplScrollTest : public LayerImplTest {
 public:
  LayerImplScrollTest() : LayerImplScrollTest(LayerListSettings()) {}

  explicit LayerImplScrollTest(const LayerTreeSettings& settings)
      : LayerImplTest(settings) {
    LayerImpl* root = root_layer();
    root->SetBounds(gfx::Size(1, 1));

    layer_ = AddLayer<LayerImpl>();
    SetElementIdsForTesting();
    // Set the max scroll offset by noting that the root layer has bounds (1,1),
    // thus whatever bounds are set for the layer will be the max scroll
    // offset plus 1 in each direction.
    layer_->SetBounds(gfx::Size(51, 81));
    CopyProperties(root, layer_);
    CreateTransformNode(layer_);
    CreateScrollNode(layer_, gfx::Size(1, 1));
    UpdateActiveTreeDrawProperties();
  }

  LayerImpl* layer() { return layer_; }

  ScrollTree* scroll_tree(LayerImpl* layer_impl) {
    return &layer_impl->layer_tree_impl()
                ->property_trees()
                ->scroll_tree_mutable();
  }

 private:
  raw_ptr<LayerImpl> layer_;
};

class CommitToPendingTreeLayerImplScrollTest : public LayerImplScrollTest {
 public:
  CommitToPendingTreeLayerImplScrollTest() : LayerImplScrollTest(settings()) {}

  LayerTreeSettings settings() {
    LayerListSettings settings;
    settings.commit_to_active_tree = false;
    return settings;
  }
};

TEST_F(LayerImplScrollTest, ScrollByWithZeroOffset) {
  // Test that LayerImpl::ScrollBy only affects ScrollDelta and total scroll
  // offset is bounded by the range [0, max scroll offset].

  EXPECT_POINTF_EQ(gfx::PointF(), CurrentScrollOffset(layer()));
  EXPECT_POINTF_EQ(gfx::PointF(),
                   scroll_tree(layer())->GetScrollOffsetBaseForTesting(
                       layer()->element_id()));
  EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(), ScrollDelta(layer()));

  layer()->ScrollBy(gfx::Vector2dF(-100, 100));
  EXPECT_POINTF_EQ(gfx::PointF(0, 80), CurrentScrollOffset(layer()));

  EXPECT_POINTF_EQ(gfx::PointAtOffsetFromOrigin(ScrollDelta(layer())),
                   CurrentScrollOffset(layer()));
  EXPECT_POINTF_EQ(gfx::PointF(),
                   scroll_tree(layer())->GetScrollOffsetBaseForTesting(
                       layer()->element_id()));

  layer()->ScrollBy(gfx::Vector2dF(100, -100));
  EXPECT_POINTF_EQ(gfx::PointF(50, 0), CurrentScrollOffset(layer()));

  EXPECT_POINTF_EQ(gfx::PointAtOffsetFromOrigin(ScrollDelta(layer())),
                   CurrentScrollOffset(layer()));
  EXPECT_POINTF_EQ(gfx::PointF(),
                   scroll_tree(layer())->GetScrollOffsetBaseForTesting(
                       layer()->element_id()));
}

TEST_F(LayerImplScrollTest, ScrollByWithNonZeroOffset) {
  gfx::PointF scroll_offset(10, 5);
  scroll_tree(layer())->UpdateScrollOffsetBaseForTesting(layer()->element_id(),
                                                         scroll_offset);

  EXPECT_POINTF_EQ(scroll_offset, CurrentScrollOffset(layer()));
  EXPECT_POINTF_EQ(scroll_offset,
                   scroll_tree(layer())->GetScrollOffsetBaseForTesting(
                       layer()->element_id()));
  EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(), ScrollDelta(layer()));

  layer()->ScrollBy(gfx::Vector2dF(-100, 100));
  EXPECT_POINTF_EQ(gfx::PointF(0, 80), CurrentScrollOffset(layer()));

  EXPECT_POINTF_EQ(scroll_offset + ScrollDelta(layer()),
                   CurrentScrollOffset(layer()));
  EXPECT_POINTF_EQ(scroll_offset,
                   scroll_tree(layer())->GetScrollOffsetBaseForTesting(
                       layer()->element_id()));

  layer()->ScrollBy(gfx::Vector2dF(100, -100));
  EXPECT_POINTF_EQ(gfx::PointF(50, 0), CurrentScrollOffset(layer()));

  EXPECT_POINTF_EQ(scroll_offset + ScrollDelta(layer()),
                   CurrentScrollOffset(layer()));
  EXPECT_POINTF_EQ(scroll_offset,
                   scroll_tree(layer())->GetScrollOffsetBaseForTesting(
                       layer()->element_id()));
}

TEST_F(LayerImplScrollTest, ApplySentScrollsNoListener) {
  gfx::PointF scroll_offset(10, 5);
  gfx::Vector2dF scroll_delta(20.5f, 8.5f);
  gfx::Vector2d sent_scroll_delta(12, -3);

  scroll_tree(layer())->UpdateScrollOffsetBaseForTesting(layer()->element_id(),
                                                         scroll_offset);
  layer()->ScrollBy(sent_scroll_delta);
  scroll_tree(layer())->CollectScrollDeltasForTesting();
  layer()->SetCurrentScrollOffset(scroll_offset + scroll_delta);

  EXPECT_POINTF_EQ(scroll_offset + scroll_delta, CurrentScrollOffset(layer()));
  EXPECT_VECTOR2DF_EQ(scroll_delta, ScrollDelta(layer()));
  EXPECT_POINTF_EQ(scroll_offset,
                   scroll_tree(layer())->GetScrollOffsetBaseForTesting(
                       layer()->element_id()));

  scroll_tree(layer())->ApplySentScrollDeltasFromAbortedCommit();

  EXPECT_POINTF_EQ(scroll_offset + scroll_delta, CurrentScrollOffset(layer()));
  EXPECT_VECTOR2DF_EQ(scroll_delta - sent_scroll_delta, ScrollDelta(layer()));
  EXPECT_POINTF_EQ(scroll_offset + sent_scroll_delta,
                   scroll_tree(layer())->GetScrollOffsetBaseForTesting(
                       layer()->element_id()));
}

TEST_F(LayerImplScrollTest, ScrollUserUnscrollableLayer) {
  gfx::PointF scroll_offset(10, 5);
  gfx::Vector2dF scroll_delta(20.5f, 8.5f);

  GetScrollNode(layer())->user_scrollable_vertical = false;
  UpdateDrawProperties(layer()->layer_tree_impl());
  scroll_tree(layer())->UpdateScrollOffsetBaseForTesting(layer()->element_id(),
                                                         scroll_offset);
  gfx::Vector2dF unscrolled = layer()->ScrollBy(scroll_delta);

  EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0, 8.5f), unscrolled);
  EXPECT_POINTF_EQ(gfx::PointF(30.5f, 5), CurrentScrollOffset(layer()));
}

// |LayerImpl::all_touch_action_regions_| is a cache of all regions on
// |LayerImpl::touch_action_region_| and must be invalidated on changes.
TEST_F(LayerImplScrollTest, TouchActionRegionCacheInvalidation) {
  host_impl()->CreatePendingTree();
  std::unique_ptr<LayerImpl> pending_layer =
      LayerImpl::Create(host_impl()->pending_tree(), 2);

  TouchActionRegion region;
  region.Union(TouchAction::kNone, gfx::Rect(0, 0, 50, 50));
  pending_layer->SetTouchActionRegion(region);

  // The values for GetAllTouchActionRegions should be correct on both layers.
  // Note that querying GetAllTouchActionRegions will update the cached value
  // in |LayerImpl::all_touch_action_regions_|.
  EXPECT_EQ(pending_layer->GetAllTouchActionRegions(), region.GetAllRegions());
  EXPECT_EQ(layer()->GetAllTouchActionRegions(), Region());

  pending_layer->PushPropertiesTo(layer());

  // After pushing properties, the value for GetAllTouchActionRegions should
  // not be stale.
  EXPECT_EQ(pending_layer->GetAllTouchActionRegions(), region.GetAllRegions());
  EXPECT_EQ(layer()->GetAllTouchActionRegions(), region.GetAllRegions());
}

TEST_F(CommitToPendingTreeLayerImplScrollTest,
       PushPropertiesToMirrorsCurrentScrollOffset) {
  gfx::PointF scroll_offset(10, 5);
  gfx::Vector2dF scroll_delta(12, 18);

  host_impl()->CreatePendingTree();

  scroll_tree(layer())->UpdateScrollOffsetBaseForTesting(layer()->element_id(),
                                                         scroll_offset);
  gfx::Vector2dF unscrolled = layer()->ScrollBy(scroll_delta);

  EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0, 0), unscrolled);
  EXPECT_POINTF_EQ(gfx::PointF(22, 23), CurrentScrollOffset(layer()));

  scroll_tree(layer())->CollectScrollDeltasForTesting();

  std::unique_ptr<LayerImpl> pending_layer =
      LayerImpl::Create(host_impl()->sync_tree(), layer()->id());
  pending_layer->SetElementId(
      LayerIdToElementIdForTesting(pending_layer->id()));
  scroll_tree(pending_layer.get())
      ->UpdateScrollOffsetBaseForTesting(pending_layer->element_id(),
                                         CurrentScrollOffset(layer()));

  pending_layer->PushPropertiesTo(layer());

  EXPECT_POINTF_EQ(gfx::PointF(22, 23), CurrentScrollOffset(layer()));
  EXPECT_POINTF_EQ(CurrentScrollOffset(layer()),
                   CurrentScrollOffset(pending_layer.get()));
}

TEST_F(LayerImplTest, JitterTest) {
  host_impl()->CreatePendingTree();
  auto* root_layer = EnsureRootLayerInPendingTree();
  root_layer->SetBounds(gfx::Size(50, 50));
  SetupViewport(root_layer, gfx::Size(100, 100), gfx::Size(100, 100));
  auto* scroll_layer =
      host_impl()->pending_tree()->InnerViewportScrollLayerForTesting();
  auto* content_layer = AddLayerInPendingTree<LayerImpl>();
  content_layer->SetBounds(gfx::Size(100, 100));
  content_layer->SetDrawsContent(true);
  CopyProperties(
      host_impl()->pending_tree()->OuterViewportScrollLayerForTesting(),
      content_layer);
  UpdatePendingTreeDrawProperties();

  host_impl()->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f);
  const int scroll = 5;
  int accumulated_scroll = 0;
  for (int i = 0; i < LayerTreeImpl::kFixedPointHitsThreshold + 1; ++i) {
    host_impl()->ActivateSyncTree();
    accumulated_scroll += scroll;
    SetScrollOffset(
        host_impl()->active_tree()->InnerViewportScrollLayerForTesting(),
        gfx::PointF(0, accumulated_scroll));
    UpdateActiveTreeDrawProperties();

    host_impl()->CreatePendingTree();
    LayerTreeImpl* pending_tree = host_impl()->pending_tree();
    pending_tree->set_source_frame_number(i + 1);
    pending_tree->PushPageScaleFromMainThread(1.f, 1.f, 1.f);
    // Simulate scroll offset pushed from the main thread.
    SetScrollOffset(scroll_layer, gfx::PointF(0, accumulated_scroll));
    // The scroll done on the active tree is undone on the pending tree.
    content_layer->SetOffsetToTransformParent(
        gfx::Vector2dF(0, accumulated_scroll));
    content_layer->SetNeedsPushProperties();
    UpdateDrawProperties(pending_tree);

    float jitter = content_layer->CalculateJitter();
    // There should not be any jitter measured till we hit the fixed point hits
    // threshold. 250 is sqrt(50 * 50) * 5. 50x50 is the visible bounds of
    // content (clipped by the viewport). 5 is the distance between the
    // locations of the content in the pending tree and the active tree.
    float expected_jitter =
        (i == pending_tree->kFixedPointHitsThreshold) ? 250 : 0;
    EXPECT_EQ(jitter, expected_jitter);
  }
}

}  // namespace
}  // namespace cc
