text:
namespace cc {
namespace {

void ExecuteCalculateDrawProperties(LayerImpl* root,
                                    LayerImplList* render_surface_layer_list) {
  // Sanity check: The test itself should create the root layer's render
  //               surface, so that the surface (and its damage tracker) can
  //               persist across multiple calls to this function.
  ASSERT_FALSE(render_surface_layer_list->size());

  FakeLayerTreeHostImpl::RecursiveUpdateNumChildren(root);
  LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
      root, root->bounds(), render_surface_layer_list);
  LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
  ASSERT_TRUE(root->render_surface());
}

void ClearDamageForAllSurfaces(LayerImpl* root) {
  for (auto* layer : *root->layer_tree_impl()) {
    if (layer->render_surface())
      layer->render_surface()->damage_tracker()->DidDrawDamagedArea();
  }
}

void EmulateDrawingOneFrame(LayerImpl* root) {
  // This emulates only steps that are relevant to testing the damage tracker:
  //   1. computing the render passes and layerlists
  //   2. updating all damage trackers in the correct order
  //   3. resetting all update_rects and property_changed flags for all layers
  //      and surfaces.

  LayerImplList render_surface_layer_list;
  ExecuteCalculateDrawProperties(root, &render_surface_layer_list);

  // Iterate back-to-front, so that damage correctly propagates from descendant
  // surfaces to ancestors.
  size_t render_surface_layer_list_size = render_surface_layer_list.size();
  for (size_t i = 0; i < render_surface_layer_list_size; ++i) {
    size_t index = render_surface_layer_list_size - 1 - i;
    RenderSurfaceImpl* target_surface =
        render_surface_layer_list[index]->render_surface();
    target_surface->damage_tracker()->UpdateDamageTrackingState(
        target_surface->layer_list(), target_surface,
        target_surface->SurfacePropertyChangedOnlyFromDescendant(),
        target_surface->content_rect(), target_surface->MaskLayer(),
        target_surface->Filters());
  }

  root->layer_tree_impl()->ResetAllChangeTracking();
}

class DamageTrackerTest : public testing::Test {
 public:
  DamageTrackerTest()
      : host_impl_(&task_runner_provider_,
                   &shared_bitmap_manager_,
                   &task_graph_runner_) {}

  LayerImpl* CreateTestTreeWithOneSurface() {
    host_impl_.active_tree()->DetachLayers();
    std::unique_ptr<LayerImpl> root =
        LayerImpl::Create(host_impl_.active_tree(), 1);
    std::unique_ptr<LayerImpl> child =
        LayerImpl::Create(host_impl_.active_tree(), 2);

    root->SetPosition(gfx::PointF());
    root->SetBounds(gfx::Size(500, 500));
    root->SetDrawsContent(true);
    root->test_properties()->force_render_surface = true;

    child->SetPosition(gfx::PointF(100.f, 100.f));
    child->SetBounds(gfx::Size(30, 30));
    child->SetDrawsContent(true);
    root->test_properties()->AddChild(std::move(child));
    host_impl_.active_tree()->SetRootLayerForTesting(std::move(root));

    return host_impl_.active_tree()->root_layer_for_testing();
  }

  LayerImpl* CreateTestTreeWithTwoSurfaces() {
    // This test tree has two render surfaces: one for the root, and one for
    // child1. Additionally, the root has a second child layer, and child1 has
    // two children of its own.

    host_impl_.active_tree()->DetachLayers();
    std::unique_ptr<LayerImpl> root =
        LayerImpl::Create(host_impl_.active_tree(), 1);
    std::unique_ptr<LayerImpl> child1 =
        LayerImpl::Create(host_impl_.active_tree(), 2);
    std::unique_ptr<LayerImpl> child2 =
        LayerImpl::Create(host_impl_.active_tree(), 3);
    std::unique_ptr<LayerImpl> grand_child1 =
        LayerImpl::Create(host_impl_.active_tree(), 4);
    std::unique_ptr<LayerImpl> grand_child2 =
        LayerImpl::Create(host_impl_.active_tree(), 5);

    root->SetPosition(gfx::PointF());
    root->SetBounds(gfx::Size(500, 500));
    root->SetDrawsContent(true);
    root->test_properties()->force_render_surface = true;

    child1->SetPosition(gfx::PointF(100.f, 100.f));
    child1->SetBounds(gfx::Size(30, 30));
    // With a child that draws_content, opacity will cause the layer to create
    // its own RenderSurface. This layer does not draw, but is intended to
    // create its own RenderSurface.
    child1->SetDrawsContent(false);
    child1->test_properties()->force_render_surface = true;

    child2->SetPosition(gfx::PointF(11.f, 11.f));
    child2->SetBounds(gfx::Size(18, 18));
    child2->SetDrawsContent(true);

    grand_child1->SetPosition(gfx::PointF(200.f, 200.f));
    grand_child1->SetBounds(gfx::Size(6, 8));
    grand_child1->SetDrawsContent(true);

    grand_child2->SetPosition(gfx::PointF(190.f, 190.f));
    grand_child2->SetBounds(gfx::Size(6, 8));
    grand_child2->SetDrawsContent(true);

    child1->test_properties()->AddChild(std::move(grand_child1));
    child1->test_properties()->AddChild(std::move(grand_child2));
    root->test_properties()->AddChild(std::move(child1));
    root->test_properties()->AddChild(std::move(child2));
    host_impl_.active_tree()->SetRootLayerForTesting(std::move(root));

    return host_impl_.active_tree()->root_layer_for_testing();
  }

  LayerImpl* CreateAndSetUpTestTreeWithOneSurface() {
    LayerImpl* root = CreateTestTreeWithOneSurface();

    // Setup includes going past the first frame which always damages
    // everything, so that we can actually perform specific tests.
    root->layer_tree_impl()->property_trees()->needs_rebuild = true;
    EmulateDrawingOneFrame(root);

    return root;
  }

  LayerImpl* CreateAndSetUpTestTreeWithTwoSurfaces() {
    LayerImpl* root = CreateTestTreeWithTwoSurfaces();

    // Setup includes going past the first frame which always damages
    // everything, so that we can actually perform specific tests.
    root->layer_tree_impl()->property_trees()->needs_rebuild = true;
    EmulateDrawingOneFrame(root);

    return root;
  }

 protected:
  FakeImplTaskRunnerProvider task_runner_provider_;
  TestSharedBitmapManager shared_bitmap_manager_;
  TestTaskGraphRunner task_graph_runner_;
  FakeLayerTreeHostImpl host_impl_;
};

TEST_F(DamageTrackerTest, SanityCheckTestTreeWithOneSurface) {
  // Sanity check that the simple test tree will actually produce the expected
  // render surfaces and layer lists.

  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();

  EXPECT_EQ(2u, root->render_surface()->layer_list().size());
  EXPECT_EQ(1, root->render_surface()->layer_list()[0]->id());
  EXPECT_EQ(2, root->render_surface()->layer_list()[1]->id());

  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();

  EXPECT_EQ(gfx::Rect(500, 500).ToString(), root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, SanityCheckTestTreeWithTwoSurfaces) {
  // Sanity check that the complex test tree will actually produce the expected
  // render surfaces and layer lists.

  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();

  LayerImpl* child1 = root->test_properties()->children[0];
  LayerImpl* child2 = root->test_properties()->children[1];
  gfx::Rect child_damage_rect =
      child1->render_surface()->damage_tracker()->current_damage_rect();
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();

  ASSERT_TRUE(child1->render_surface());
  EXPECT_FALSE(child2->render_surface());
  EXPECT_EQ(3u, root->render_surface()->layer_list().size());
  EXPECT_EQ(2u, child1->render_surface()->layer_list().size());

  // The render surface for child1 only has a content_rect that encloses
  // grand_child1 and grand_child2, because child1 does not draw content.
  EXPECT_EQ(gfx::Rect(190, 190, 16, 18).ToString(),
            child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(500, 500).ToString(), root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];

  // CASE 1: Setting the update rect should cause the corresponding damage to
  //         the surface.
  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(10, 11, 12, 13));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damage position on the surface should be: position of update_rect (10, 11)
  // relative to the child (100, 100).
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(110, 111, 12, 13).ToString(),
            root_damage_rect.ToString());

  // CASE 2: The same update rect twice in a row still produces the same
  //         damage.
  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(10, 11, 12, 13));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(110, 111, 12, 13).ToString(),
            root_damage_rect.ToString());

  // CASE 3: Setting a different update rect should cause damage on the new
  //         update region, but no additional exposed old region.
  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(20, 25, 1, 2));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damage position on the surface should be: position of update_rect (20, 25)
  // relative to the child (100, 100).
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(120, 125, 1, 2).ToString(), root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];

  // CASE 1: Adding the layer damage rect should cause the corresponding damage
  // to the surface.
  ClearDamageForAllSurfaces(root);
  child->AddDamageRect(gfx::Rect(10, 11, 12, 13));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damage position on the surface should be: position of layer damage_rect
  // (10, 11) relative to the child (100, 100).
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 12, 13)));

  // CASE 2: The same layer damage rect twice in a row still produces the same
  // damage.
  ClearDamageForAllSurfaces(root);
  child->AddDamageRect(gfx::Rect(10, 11, 12, 13));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 12, 13)));

  // CASE 3: Adding a different layer damage rect should cause damage on the
  // new damaged region, but no additional exposed old region.
  ClearDamageForAllSurfaces(root);
  child->AddDamageRect(gfx::Rect(20, 25, 1, 2));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damage position on the surface should be: position of layer damage_rect
  // (20, 25) relative to the child (100, 100).
  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(120, 125, 1, 2)));

  // CASE 4: Adding multiple layer damage rects should cause a unified
  // damage on root damage rect.
  ClearDamageForAllSurfaces(root);
  child->AddDamageRect(gfx::Rect(20, 25, 1, 2));
  child->AddDamageRect(gfx::Rect(10, 15, 3, 4));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damage position on the surface should be: position of layer damage_rect
  // (20, 25) relative to the child (100, 100).
  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(120, 125, 1, 2)));
  EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 115, 3, 4)));
}

TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];

  // CASE 1: Adding the layer damage rect and update rect should cause the
  // corresponding damage to the surface.
  ClearDamageForAllSurfaces(root);
  child->AddDamageRect(gfx::Rect(5, 6, 12, 13));
  child->SetUpdateRect(gfx::Rect(15, 16, 14, 10));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damage position on the surface should be: position of unified layer
  // damage_rect and update rect (5, 6)
  // relative to the child (100, 100).
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(105, 106, 24, 20)));

  // CASE 2: The same layer damage rect and update rect twice in a row still
  // produces the same damage.
  ClearDamageForAllSurfaces(root);
  child->AddDamageRect(gfx::Rect(10, 11, 12, 13));
  child->SetUpdateRect(gfx::Rect(10, 11, 14, 15));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 14, 15)));

  // CASE 3: Adding a different layer damage rect and update rect should cause
  // damage on the new damaged region, but no additional exposed old region.
  ClearDamageForAllSurfaces(root);
  child->AddDamageRect(gfx::Rect(20, 25, 2, 3));
  child->SetUpdateRect(gfx::Rect(5, 10, 7, 8));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damage position on the surface should be: position of unified layer damage
  // rect and update rect (5, 10) relative to the child (100, 100).
  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(105, 110, 17, 18)));
}

TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];

  // CASE 1: The layer's property changed flag takes priority over update rect.
  //
  child->test_properties()->force_render_surface = true;
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(10, 11, 12, 13));
  child->OnOpacityAnimated(0.5f);
  EmulateDrawingOneFrame(root);

  ASSERT_EQ(2u, root->render_surface()->layer_list().size());

  // Damage should be the entire child layer in target_surface space.
  gfx::Rect expected_rect = gfx::Rect(100, 100, 30, 30);
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(expected_rect.ToString(), root_damage_rect.ToString());

  // CASE 2: If a layer moves due to property change, it damages both the new
  //         location and the old (exposed) location. The old location is the
  //         entire old layer, not just the update_rect.

  // Cycle one frame of no change, just to sanity check that the next rect is
  // not because of the old damage state.
  ClearDamageForAllSurfaces(root);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(root_damage_rect.IsEmpty());

  // Then, test the actual layer movement.
  ClearDamageForAllSurfaces(root);
  child->SetPosition(gfx::PointF(200.f, 230.f));
  child->NoteLayerPropertyChanged();
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Expect damage to be the combination of the previous one and the new one.
  expected_rect.Union(gfx::Rect(200, 230, 30, 30));
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_FLOAT_RECT_EQ(expected_rect, root_damage_rect);
}

TEST_F(DamageTrackerTest, VerifyDamageWhenSurfaceRemoved) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* surface = root->test_properties()->children[0];
  LayerImpl* child = surface->test_properties()->children[0];
  child->SetDrawsContent(true);
  EmulateDrawingOneFrame(root);
  ClearDamageForAllSurfaces(root);

  surface->test_properties()->force_render_surface = false;
  child->SetDrawsContent(false);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(290, 290, 16, 18).ToString(),
            root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForTransformedLayer) {
  // If a layer is transformed, the damage rect should still enclose the entire
  // transformed layer.

  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];
  child->test_properties()->force_render_surface = true;

  gfx::Transform rotation;
  rotation.Rotate(45.0);

  ClearDamageForAllSurfaces(root);
  child->test_properties()->transform_origin = gfx::Point3F(
      child->bounds().width() * 0.5f, child->bounds().height() * 0.5f, 0.f);
  child->SetPosition(gfx::PointF(85.f, 85.f));
  child->NoteLayerPropertyChanged();
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check that the layer actually moved to (85, 85), damaging its old
  // location and new location.
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(85, 85, 45, 45).ToString(), root_damage_rect.ToString());

  // With the anchor on the layer's center, now we can test the rotation more
  // intuitively, since it applies about the layer's anchor.
  ClearDamageForAllSurfaces(root);
  child->OnTransformAnimated(rotation);
  EmulateDrawingOneFrame(root);

  // Since the child layer is square, rotation by 45 degrees about the center
  // should increase the size of the expected rect by sqrt(2), centered around
  // (100, 100). The old exposed region should be fully contained in the new
  // region.
  float expected_width = 30.f * sqrt(2.f);
  float expected_position = 100.f - 0.5f * expected_width;
  gfx::Rect expected_rect = gfx::ToEnclosingRect(gfx::RectF(
      expected_position, expected_position, expected_width, expected_width));
  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(expected_rect.ToString(), root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForPerspectiveClippedLayer) {
  // If a layer has a perspective transform that causes w < 0, then not
  // clipping the layer can cause an invalid damage rect. This test checks that
  // the w < 0 case is tracked properly.
  //
  // The transform is constructed so that if w < 0 clipping is not performed,
  // the incorrect rect will be very small, specifically: position (500.972504,
  // 498.544617) and size 0.056610 x 2.910767.  Instead, the correctly
  // transformed rect should actually be very huge (i.e. in theory, -infinity
  // on the left), and positioned so that the right-most bound rect will be
  // approximately 501 units in root surface space.
  //

  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];

  gfx::Transform transform;
  transform.Translate3d(550.0, 500.0, 0.0);
  transform.ApplyPerspectiveDepth(1.0);
  transform.RotateAboutYAxis(45.0);
  transform.Translate3d(-50.0, -50.0, 0.0);

  // Set up the child
  child->SetPosition(gfx::PointF(0.f, 0.f));
  child->SetBounds(gfx::Size(100, 100));
  child->SetTransform(transform);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check that the child layer's bounds would actually get clipped by
  // w < 0, otherwise this test is not actually testing the intended scenario.
  gfx::QuadF test_quad(gfx::RectF(gfx::PointF(), gfx::SizeF(100.f, 100.f)));
  bool clipped = false;
  MathUtil::MapQuad(transform, test_quad, &clipped);
  EXPECT_TRUE(clipped);

  // Damage the child without moving it.
  child->test_properties()->force_render_surface = true;
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  ClearDamageForAllSurfaces(root);
  child->OnOpacityAnimated(0.5f);
  EmulateDrawingOneFrame(root);

  // The expected damage should cover the entire root surface (500x500), but we
  // don't care whether the damage rect was clamped or is larger than the
  // surface for this test.
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  gfx::Rect damage_we_care_about = gfx::Rect(gfx::Size(500, 500));
  EXPECT_TRUE(root_damage_rect.Contains(damage_we_care_about));
}

TEST_F(DamageTrackerTest, VerifyDamageForBlurredSurface) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* surface = root->test_properties()->children[0];
  LayerImpl* child = surface->test_properties()->children[0];

  FilterOperations filters;
  filters.Append(FilterOperation::CreateBlurFilter(5.f));

  // Setting the filter will damage the whole surface.
  ClearDamageForAllSurfaces(root);
  surface->test_properties()->filters = filters;
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Setting the update rect should cause the corresponding damage to the
  // surface, blurred based on the size of the blur filter.
  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(1, 2, 3, 4));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damage position on the surface should be: position of update_rect (1, 2)
  // relative to the child (300, 300), but expanded by the blur outsets
  // (15, since the blur radius is 5).
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(286, 287, 33, 34), root_damage_rect);
}

TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];
  gfx::Rect root_damage_rect, child_damage_rect;

  // Allow us to set damage on child too.
  child->SetDrawsContent(true);

  FilterOperations filters;
  filters.Append(FilterOperation::CreateReferenceFilter(
      SkBlurImageFilter::Make(2, 2, nullptr)));

  // Setting the filter will damage the whole surface.
  ClearDamageForAllSurfaces(root);
  child->test_properties()->force_render_surface = true;
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child->OnFilterAnimated(filters);
  EmulateDrawingOneFrame(root);
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  child_damage_rect =
          child->render_surface()->damage_tracker()->current_damage_rect();

  // gfx::Rect(100, 100, 30, 30), expanded by 6px for the 2px blur filter.
  EXPECT_EQ(gfx::Rect(94, 94, 42, 42), root_damage_rect);

  // gfx::Rect(0, 0, 30, 30), expanded by 6px for the 2px blur filter.
  EXPECT_EQ(gfx::Rect(-6, -6, 42, 42), child_damage_rect);

  // CASE 1: Setting the update rect should damage the whole surface (for now)
  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(1, 1));
  EmulateDrawingOneFrame(root);

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  child_damage_rect =
          child->render_surface()->damage_tracker()->current_damage_rect();

  // gfx::Rect(100, 100, 1, 1), expanded by 6px for the 2px blur filter.
  EXPECT_EQ(gfx::Rect(94, 94, 13, 13), root_damage_rect);

  // gfx::Rect(0, 0, 1, 1), expanded by 6px for the 2px blur filter.
  EXPECT_EQ(gfx::Rect(-6, -6, 13, 13), child_damage_rect);
}

TEST_F(DamageTrackerTest, VerifyDamageForTransformedImageFilter) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];
  gfx::Rect root_damage_rect, child_damage_rect;

  // Allow us to set damage on child too.
  child->SetDrawsContent(true);

  FilterOperations filters;
  filters.Append(FilterOperation::CreateReferenceFilter(
      SkBlurImageFilter::Make(2, 2, nullptr)));

  // Setting the filter will damage the whole surface.
  gfx::Transform transform;
  transform.RotateAboutYAxis(60);
  ClearDamageForAllSurfaces(root);
  child->test_properties()->force_render_surface = true;
  child->SetTransform(transform);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child->OnFilterAnimated(filters);
  EmulateDrawingOneFrame(root);
  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  child_damage_rect =
      child->render_surface()->damage_tracker()->current_damage_rect();

  // Blur outset is 6px for a 2px blur.
  int blur_outset = 6;
  int rotated_outset_left = blur_outset / 2;
  int expected_rotated_width = (30 + 2 * blur_outset) / 2;
  gfx::Rect expected_root_damage(100 - rotated_outset_left, 100 - blur_outset,
                                 expected_rotated_width, 30 + 2 * blur_outset);
  expected_root_damage.Union(gfx::Rect(100, 100, 30, 30));
  EXPECT_EQ(expected_root_damage, root_damage_rect);
  EXPECT_EQ(gfx::Rect(-blur_outset, -blur_outset, 30 + 2 * blur_outset,
                      30 + 2 * blur_outset),
            child_damage_rect);

  // Setting the update rect should damage the whole surface (for now)
  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(30, 30));
  EmulateDrawingOneFrame(root);

  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  child_damage_rect =
      child->render_surface()->damage_tracker()->current_damage_rect();

  int expect_width = 30 + 2 * blur_outset;
  int expect_height = 30 + 2 * blur_outset;
  EXPECT_EQ(gfx::Rect(100 - blur_outset / 2, 100 - blur_outset,
                      expect_width / 2, expect_height),
            root_damage_rect);
  EXPECT_EQ(gfx::Rect(-blur_outset, -blur_outset, expect_width, expect_height),
            child_damage_rect);
}

TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  LayerImpl* child2 = root->test_properties()->children[1];

  // Allow us to set damage on child1 too.
  child1->SetDrawsContent(true);

  FilterOperations filters;
  filters.Append(FilterOperation::CreateBlurFilter(2.f));

  // Setting the filter will damage the whole surface.
  ClearDamageForAllSurfaces(root);
  child1->test_properties()->background_filters = filters;
  child1->NoteLayerPropertyChanged();
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // CASE 1: Setting the update rect should cause the corresponding damage to
  //         the surface, blurred based on the size of the child's background
  //         blur filter. Note that child1's render surface has a size of
  //         206x208 due to contributions from grand_child1 and grand_child2.
  ClearDamageForAllSurfaces(root);
  root->SetUpdateRect(gfx::Rect(297, 297, 2, 2));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  // Damage position on the surface should be a composition of the damage on
  // the root and on child2.  Damage on the root should be: position of
  // update_rect (297, 297), but expanded by the blur outsets.
  gfx::Rect expected_damage_rect = gfx::Rect(297, 297, 2, 2);

  // 6px spread for a 2px blur.
  expected_damage_rect.Inset(-6, -6, -6, -6);
  EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());

  // CASE 2: Setting the update rect should cause the corresponding damage to
  //         the surface, blurred based on the size of the child's background
  //         blur filter. Since the damage extends to the right/bottom outside
  //         of the blurred layer, only the left/top should end up expanded.
  ClearDamageForAllSurfaces(root);
  root->SetUpdateRect(gfx::Rect(297, 297, 30, 30));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  // Damage position on the surface should be a composition of the damage on
  // the root and on child2.  Damage on the root should be: position of
  // update_rect (297, 297), but expanded on the left/top by the blur outsets.
  expected_damage_rect = gfx::Rect(297, 297, 30, 30);

  // 6px spread for a 2px blur.
  expected_damage_rect.Inset(-6, -6, 0, 0);
  EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());

  // CASE 3: Setting this update rect outside the blurred content_bounds of the
  //         blurred child1 will not cause it to be expanded.
  ClearDamageForAllSurfaces(root);
  root->SetUpdateRect(gfx::Rect(30, 30, 2, 2));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  // Damage on the root should be: position of update_rect (30, 30), not
  // expanded.
  expected_damage_rect = gfx::Rect(30, 30, 2, 2);

  EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());

  // CASE 4: Setting this update rect inside the blurred content_bounds but
  //         outside the original content_bounds of the blurred child1 will
  //         cause it to be expanded.
  ClearDamageForAllSurfaces(root);
  root->SetUpdateRect(gfx::Rect(99, 99, 1, 1));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  // Damage on the root should be: the originally damaged rect (99,99 1x1)
  // plus the rect that can influence with a 2px blur (93,93 13x13) intersected
  // with the surface rect (100,100 206x208). So no additional damage occurs
  // above or to the left, but there is additional damage within the blurred
  // area.
  expected_damage_rect = gfx::Rect(99, 99, 7, 7);
  EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());

  // CASE 5: Setting the update rect on child2, which is above child1, will
  // not get blurred by child1, so it does not need to get expanded.
  ClearDamageForAllSurfaces(root);
  child2->SetUpdateRect(gfx::Rect(1, 1));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  // Damage on child2 should be: position of update_rect offset by the child's
  // position (11, 11), and not expanded by anything.
  expected_damage_rect = gfx::Rect(11, 11, 1, 1);

  EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());

  // CASE 6: Setting the update rect on child1 will also blur the damage, so
  //         that any pixels needed for the blur are redrawn in the current
  //         frame.
  ClearDamageForAllSurfaces(root);
  child1->SetUpdateRect(gfx::Rect(1, 1));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  // Damage on child1 should be: position of update_rect offset by the child's
  // position (100, 100), and expanded by the damage.

  // Damage should be (0,0 1x1), offset by the 100,100 offset of child1 in
  // root, and expanded 6px for the 2px blur (i.e., 94,94 13x13), but there
  // should be no damage outside child1 (i.e. none above or to the left of
  // 100,100.
  expected_damage_rect = gfx::Rect(100, 100, 7, 7);
  EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child1 = root->test_properties()->children[0];

  // CASE 1: Adding a new layer should cause the appropriate damage.
  //
  ClearDamageForAllSurfaces(root);
  {
    std::unique_ptr<LayerImpl> child2 =
        LayerImpl::Create(host_impl_.active_tree(), 3);
    child2->SetPosition(gfx::PointF(400.f, 380.f));
    child2->SetBounds(gfx::Size(6, 8));
    child2->SetDrawsContent(true);
    root->test_properties()->AddChild(std::move(child2));
  }
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check - all 3 layers should be on the same render surface; render
  // surfaces are tested elsewhere.
  ASSERT_EQ(3u, root->render_surface()->layer_list().size());

  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(400, 380, 6, 8).ToString(), root_damage_rect.ToString());

  // CASE 2: If the layer is removed, its entire old layer becomes exposed, not
  //         just the last update rect.

  // Advance one frame without damage so that we know the damage rect is not
  // leftover from the previous case.
  ClearDamageForAllSurfaces(root);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(root_damage_rect.IsEmpty());

  // Then, test removing child1.
  root->test_properties()->RemoveChild(child1);
  child1 = NULL;
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(100, 100, 30, 30).ToString(),
            root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForNewUnchangedLayer) {
  // If child2 is added to the layer tree, but it doesn't have any explicit
  // damage of its own, it should still indeed damage the target surface.

  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();

  ClearDamageForAllSurfaces(root);
  {
    std::unique_ptr<LayerImpl> child2 =
        LayerImpl::Create(host_impl_.active_tree(), 3);
    child2->SetPosition(gfx::PointF(400.f, 380.f));
    child2->SetBounds(gfx::Size(6, 8));
    child2->SetDrawsContent(true);
    root->test_properties()->AddChild(std::move(child2));
    root->layer_tree_impl()->BuildLayerListForTesting();
    host_impl_.active_tree()->ResetAllChangeTracking();
    LayerImpl* child2_ptr = host_impl_.active_tree()->LayerById(3);
    // Sanity check the initial conditions of the test, if these asserts
    // trigger, it means the test no longer actually covers the intended
    // scenario.
    ASSERT_FALSE(child2_ptr->LayerPropertyChanged());
    ASSERT_TRUE(child2_ptr->update_rect().IsEmpty());
  }
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check - all 3 layers should be on the same render surface; render
  // surfaces are tested elsewhere.
  ASSERT_EQ(3u, root->render_surface()->layer_list().size());

  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(400, 380, 6, 8).ToString(), root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForMultipleLayers) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child1 = root->test_properties()->children[0];

  // In this test we don't want the above tree manipulation to be considered
  // part of the same frame.
  ClearDamageForAllSurfaces(root);
  {
    std::unique_ptr<LayerImpl> child2 =
        LayerImpl::Create(host_impl_.active_tree(), 3);
    child2->SetPosition(gfx::PointF(400.f, 380.f));
    child2->SetBounds(gfx::Size(6, 8));
    child2->SetDrawsContent(true);
    root->test_properties()->AddChild(std::move(child2));
  }
  LayerImpl* child2 = root->test_properties()->children[1];
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Damaging two layers simultaneously should cause combined damage.
  // - child1 update rect in surface space: gfx::Rect(100, 100, 1, 2);
  // - child2 update rect in surface space: gfx::Rect(400, 380, 3, 4);
  ClearDamageForAllSurfaces(root);
  child1->SetUpdateRect(gfx::Rect(1, 2));
  child2->SetUpdateRect(gfx::Rect(3, 4));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(100, 100, 303, 284).ToString(),
            root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForNestedSurfaces) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  LayerImpl* child2 = root->test_properties()->children[1];
  LayerImpl* grand_child1 =
      root->test_properties()->children[0]->test_properties()->children[0];
  child2->test_properties()->force_render_surface = true;
  grand_child1->test_properties()->force_render_surface = true;
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  gfx::Rect child_damage_rect;
  gfx::Rect root_damage_rect;

  // CASE 1: Damage to a descendant surface should propagate properly to
  //         ancestor surface.
  ClearDamageForAllSurfaces(root);
  grand_child1->OnOpacityAnimated(0.5f);
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(200, 200, 6, 8).ToString(), child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(300, 300, 6, 8).ToString(), root_damage_rect.ToString());

  // CASE 2: Same as previous case, but with additional damage elsewhere that
  //         should be properly unioned.
  // - child1 surface damage in root surface space:
  //   gfx::Rect(300, 300, 6, 8);
  // - child2 damage in root surface space:
  //   gfx::Rect(11, 11, 18, 18);
  ClearDamageForAllSurfaces(root);
  grand_child1->OnOpacityAnimated(0.7f);
  child2->OnOpacityAnimated(0.7f);
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(200, 200, 6, 8).ToString(), child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(11, 11, 295, 297).ToString(),
            root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromDescendantLayer) {
  // If descendant layer changes and affects the content bounds of the render
  // surface, then the entire descendant surface should be damaged, and it
  // should damage its ancestor surface with the old and new surface regions.

  // This is a tricky case, since only the first grand_child changes, but the
  // entire surface should be marked dirty.

  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  LayerImpl* grand_child1 =
      root->test_properties()->children[0]->test_properties()->children[0];
  gfx::Rect child_damage_rect;
  gfx::Rect root_damage_rect;

  ClearDamageForAllSurfaces(root);
  grand_child1->SetPosition(gfx::PointF(195.f, 205.f));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();

  // The new surface bounds should be damaged entirely, even though only one of
  // the layers changed.
  EXPECT_EQ(gfx::Rect(190, 190, 11, 23).ToString(),
            child_damage_rect.ToString());

  // Damage to the root surface should be the union of child1's *entire* render
  // surface (in target space), and its old exposed area (also in target
  // space).
  EXPECT_EQ(gfx::Rect(290, 290, 16, 23).ToString(),
            root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromAncestorLayer) {
  // An ancestor/owning layer changes that affects the position/transform of
  // the render surface. Note that in this case, the layer_property_changed flag
  // already propagates to the subtree (tested in LayerImpltest), which damages
  // the entire child1 surface, but the damage tracker still needs the correct
  // logic to compute the exposed region on the root surface.

  // TODO(shawnsingh): the expectations of this test case should change when we
  // add support for a unique scissor_rect per RenderSurface. In that case, the
  // child1 surface should be completely unchanged, since we are only
  // transforming it, while the root surface would be damaged appropriately.

  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  LayerImpl* grand_child1 = child1->test_properties()->children[0];
  LayerImpl* grand_child2 = child1->test_properties()->children[1];
  gfx::Rect child_damage_rect;
  gfx::Rect root_damage_rect;

  ClearDamageForAllSurfaces(root);
  child1->SetPosition(gfx::PointF(50.f, 50.f));
  child1->NoteLayerPropertyChanged();
  grand_child1->NoteLayerPropertyChanged();
  grand_child2->NoteLayerPropertyChanged();
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();

  // The new surface bounds should be damaged entirely.
  EXPECT_EQ(gfx::Rect(190, 190, 16, 18).ToString(),
            child_damage_rect.ToString());

  // The entire child1 surface and the old exposed child1 surface should damage
  // the root surface.
  //  - old child1 surface in target space: gfx::Rect(290, 290, 16, 18)
  //  - new child1 surface in target space: gfx::Rect(240, 240, 16, 18)
  EXPECT_EQ(gfx::Rect(240, 240, 66, 68).ToString(),
            root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  gfx::Rect child_damage_rect;
  gfx::Rect root_damage_rect;

  // CASE 1: If a descendant surface disappears, its entire old area becomes
  //         exposed.
  ClearDamageForAllSurfaces(root);
  child1->test_properties()->force_render_surface = false;
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check that there is only one surface now.
  ASSERT_FALSE(child1->render_surface());
  ASSERT_EQ(4u, root->render_surface()->layer_list().size());

  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(290, 290, 16, 18).ToString(),
            root_damage_rect.ToString());

  // CASE 2: If a descendant surface appears, its entire old area becomes
  //         exposed.

  // Cycle one frame of no change, just to sanity check that the next rect is
  // not because of the old damage state.
  ClearDamageForAllSurfaces(root);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(root_damage_rect.IsEmpty());

  // Then change the tree so that the render surface is added back.
  ClearDamageForAllSurfaces(root);
  child1->test_properties()->force_render_surface = true;

  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check that there is a new surface now.
  ASSERT_TRUE(child1->render_surface());
  EXPECT_EQ(3u, root->render_surface()->layer_list().size());
  EXPECT_EQ(2u, child1->render_surface()->layer_list().size());

  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(190, 190, 16, 18).ToString(),
            child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(290, 290, 16, 18).ToString(),
            root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyNoDamageWhenNothingChanged) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  gfx::Rect child_damage_rect;
  gfx::Rect root_damage_rect;

  // CASE 1: If nothing changes, the damage rect should be empty.
  //
  ClearDamageForAllSurfaces(root);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(child_damage_rect.IsEmpty());
  EXPECT_TRUE(root_damage_rect.IsEmpty());

  // CASE 2: If nothing changes twice in a row, the damage rect should still be
  //         empty.
  //
  ClearDamageForAllSurfaces(root);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(child_damage_rect.IsEmpty());
  EXPECT_TRUE(root_damage_rect.IsEmpty());
}

TEST_F(DamageTrackerTest, VerifyNoDamageForUpdateRectThatDoesNotDrawContent) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  gfx::Rect child_damage_rect;
  gfx::Rect root_damage_rect;

  // In our specific tree, the update rect of child1 should not cause any
  // damage to any surface because it does not actually draw content.
  ClearDamageForAllSurfaces(root);
  child1->SetUpdateRect(gfx::Rect(1, 2));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(child_damage_rect.IsEmpty());
  EXPECT_TRUE(root_damage_rect.IsEmpty());
}

TEST_F(DamageTrackerTest, VerifyDamageForReplica) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  LayerImpl* grand_child1 = child1->test_properties()->children[0];
  LayerImpl* grand_child2 = child1->test_properties()->children[1];

  // Damage on a surface that has a reflection should cause the target surface
  // to receive the surface's damage and the surface's reflected damage.

  // For this test case, we modify grand_child2, and add grand_child3 to extend
  // the bounds of child1's surface. This way, we can test reflection changes
  // without changing content_bounds of the surface.
  grand_child2->SetPosition(gfx::PointF(180.f, 180.f));
  {
    std::unique_ptr<LayerImpl> grand_child3 =
        LayerImpl::Create(host_impl_.active_tree(), 6);
    grand_child3->SetPosition(gfx::PointF(240.f, 240.f));
    grand_child3->SetBounds(gfx::Size(10, 10));
    grand_child3->SetDrawsContent(true);
    child1->test_properties()->AddChild(std::move(grand_child3));
  }
  child1->test_properties()->opacity = 0.5f;
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // CASE 1: adding a reflection about the left edge of grand_child1.
  //
  ClearDamageForAllSurfaces(root);
  {
    std::unique_ptr<LayerImpl> grand_child1_replica =
        LayerImpl::Create(host_impl_.active_tree(), 7);
    grand_child1_replica->SetPosition(gfx::PointF());
    gfx::Transform reflection;
    reflection.Scale3d(-1.0, 1.0, 1.0);
    grand_child1_replica->SetTransform(reflection);
    grand_child1->test_properties()->SetReplicaLayer(
        std::move(grand_child1_replica));
    grand_child1->test_properties()->force_render_surface = true;
    grand_child1->NoteLayerPropertyChanged();
  }
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  gfx::Rect grand_child_damage_rect =
      grand_child1->render_surface()->damage_tracker()->current_damage_rect();
  gfx::Rect child_damage_rect =
      child1->render_surface()->damage_tracker()->current_damage_rect();
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();

  // The grand_child surface damage should not include its own replica. The
  // child surface damage should include the normal and replica surfaces.
  EXPECT_EQ(gfx::Rect(6, 8).ToString(), grand_child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(194, 200, 12, 8).ToString(),
            child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(294, 300, 12, 8).ToString(), root_damage_rect.ToString());

  // CASE 2: moving the descendant surface should cause both the original and
  //         reflected areas to be damaged on the target.
  ClearDamageForAllSurfaces(root);
  gfx::Rect old_content_rect = child1->render_surface()->content_rect();
  grand_child1->SetPosition(gfx::PointF(195.f, 205.f));
  grand_child1->NoteLayerPropertyChanged();
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  ASSERT_EQ(old_content_rect.width(),
            child1->render_surface()->content_rect().width());
  ASSERT_EQ(old_content_rect.height(),
            child1->render_surface()->content_rect().height());

  grand_child_damage_rect =
          grand_child1->render_surface()->
              damage_tracker()->current_damage_rect();
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();

  // The child surface damage should include normal and replica surfaces for
  // both old and new locations.
  //  - old location in target space: gfx::Rect(194, 200, 12, 8)
  //  - new location in target space: gfx::Rect(189, 205, 12, 8)
  EXPECT_EQ(gfx::Rect(6, 8).ToString(), grand_child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(189, 200, 17, 13).ToString(),
            child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(289, 300, 17, 13).ToString(),
            root_damage_rect.ToString());

  // CASE 3: removing the reflection should cause the entire region including
  //         reflection to damage the target surface.
  ClearDamageForAllSurfaces(root);
  grand_child1->test_properties()->SetReplicaLayer(nullptr);
  grand_child1->test_properties()->force_render_surface = false;
  grand_child1->NoteLayerPropertyChanged();
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  ASSERT_EQ(old_content_rect.width(),
            child1->render_surface()->content_rect().width());
  ASSERT_EQ(old_content_rect.height(),
            child1->render_surface()->content_rect().height());

  EXPECT_FALSE(grand_child1->render_surface());
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();

  EXPECT_EQ(gfx::Rect(189, 205, 12, 8).ToString(),
            child_damage_rect.ToString());
  EXPECT_EQ(gfx::Rect(289, 305, 12, 8).ToString(), root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForMask) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];

  // In the current implementation of the damage tracker, changes to mask
  // layers should damage the entire corresponding surface.

  ClearDamageForAllSurfaces(root);

  // Set up the mask layer.
  {
    std::unique_ptr<LayerImpl> mask_layer =
        LayerImpl::Create(host_impl_.active_tree(), 3);
    mask_layer->SetPosition(child->position());
    mask_layer->SetBounds(child->bounds());
    child->test_properties()->SetMaskLayer(std::move(mask_layer));
    child->test_properties()->force_render_surface = true;
  }
  LayerImpl* mask_layer = child->test_properties()->mask_layer;

  // Add opacity and a grand_child so that the render surface persists even
  // after we remove the mask.
  {
    std::unique_ptr<LayerImpl> grand_child =
        LayerImpl::Create(host_impl_.active_tree(), 4);
    grand_child->SetPosition(gfx::PointF(2.f, 2.f));
    grand_child->SetBounds(gfx::Size(2, 2));
    grand_child->SetDrawsContent(true);
    child->test_properties()->AddChild(std::move(grand_child));
  }
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // CASE 1: the update_rect on a mask layer should damage the entire target
  //         surface.
  ClearDamageForAllSurfaces(root);
  mask_layer->SetUpdateRect(gfx::Rect(1, 2, 3, 4));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  gfx::Rect child_damage_rect =
      child->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());

  // CASE 2: a property change on the mask layer should damage the entire
  //         target surface.

  // Advance one frame without damage so that we know the damage rect is not
  // leftover from the previous case.
  ClearDamageForAllSurfaces(root);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(child_damage_rect.IsEmpty());

  // Then test the property change.
  ClearDamageForAllSurfaces(root);
  mask_layer->NoteLayerPropertyChanged();

  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());

  // CASE 3: removing the mask also damages the entire target surface.
  //

  // Advance one frame without damage so that we know the damage rect is not
  // leftover from the previous case.
  ClearDamageForAllSurfaces(root);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  child_damage_rect =
          child->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(child_damage_rect.IsEmpty());

  // Then test mask removal.
  ClearDamageForAllSurfaces(root);
  child->test_properties()->SetMaskLayer(nullptr);
  child->NoteLayerPropertyChanged();
  ASSERT_TRUE(child->LayerPropertyChanged());
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check that a render surface still exists.
  ASSERT_TRUE(child->render_surface());

  child_damage_rect =
          child->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForReplicaMask) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  LayerImpl* grand_child1 = child1->test_properties()->children[0];

  // Changes to a replica's mask should not damage the original surface,
  // because it is not masked. But it does damage the ancestor target surface.

  ClearDamageForAllSurfaces(root);

  // Create a reflection about the left edge of grand_child1.
  {
    std::unique_ptr<LayerImpl> grand_child1_replica =
        LayerImpl::Create(host_impl_.active_tree(), 6);
    grand_child1_replica->SetPosition(gfx::PointF());
    gfx::Transform reflection;
    reflection.Scale3d(-1.0, 1.0, 1.0);
    grand_child1_replica->SetTransform(reflection);
    grand_child1->test_properties()->SetReplicaLayer(
        std::move(grand_child1_replica));
    grand_child1->test_properties()->force_render_surface = true;
  }
  LayerImpl* grand_child1_replica =
      grand_child1->test_properties()->replica_layer;

  // Set up the mask layer on the replica layer
  {
    std::unique_ptr<LayerImpl> replica_mask_layer =
        LayerImpl::Create(host_impl_.active_tree(), 7);
    replica_mask_layer->SetPosition(gfx::PointF());
    replica_mask_layer->SetBounds(grand_child1->bounds());
    grand_child1_replica->test_properties()->SetMaskLayer(
        std::move(replica_mask_layer));
  }
  LayerImpl* replica_mask_layer =
      grand_child1_replica->test_properties()->mask_layer;

  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check that the appropriate render surfaces were created
  ASSERT_TRUE(grand_child1->render_surface());

  // CASE 1: a property change on the mask should damage only the reflected
  //         region on the target surface.
  ClearDamageForAllSurfaces(root);
  replica_mask_layer->NoteLayerPropertyChanged();
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  gfx::Rect grand_child_damage_rect =
      grand_child1->render_surface()->damage_tracker()->current_damage_rect();
  gfx::Rect child_damage_rect =
      child1->render_surface()->damage_tracker()->current_damage_rect();

  EXPECT_TRUE(grand_child_damage_rect.IsEmpty());
  EXPECT_EQ(gfx::Rect(194, 200, 6, 8).ToString(), child_damage_rect.ToString());

  // CASE 2: removing the replica mask damages only the reflected region on the
  //         target surface.
  //
  ClearDamageForAllSurfaces(root);
  grand_child1_replica->test_properties()->SetMaskLayer(nullptr);
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  grand_child_damage_rect =
          grand_child1->render_surface()->damage_tracker()->
              current_damage_rect();
  child_damage_rect =
          child1->render_surface()->damage_tracker()->current_damage_rect();

  EXPECT_TRUE(grand_child_damage_rect.IsEmpty());
  EXPECT_EQ(gfx::Rect(194, 200, 6, 8).ToString(), child_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithTransformOrigin) {
  LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
  LayerImpl* child1 = root->test_properties()->children[0];
  LayerImpl* grand_child1 = child1->test_properties()->children[0];

  // Verify that the correct replica_origin_transform is used for the
  // replica_mask.
  ClearDamageForAllSurfaces(root);

  // This is not actually the transform origin point being tested, but by
  // convention its
  // expected to be the same as the replica's anchor point.
  grand_child1->test_properties()->transform_origin =
      gfx::Point3F(grand_child1->bounds().width(), 0.f, 0.f);

  {
    std::unique_ptr<LayerImpl> grand_child1_replica =
        LayerImpl::Create(host_impl_.active_tree(), 6);
    grand_child1_replica->SetPosition(gfx::PointF());

    // This is the anchor being tested.
    grand_child1_replica->test_properties()->transform_origin =
        gfx::Point3F(grand_child1->bounds().width(), 0.f, 0.f);
    gfx::Transform reflection;
    reflection.Scale3d(-1.0, 1.0, 1.0);
    grand_child1_replica->SetTransform(reflection);
    // We need to set parent on replica layer for property tree building.
    grand_child1_replica->test_properties()->parent = grand_child1;
    grand_child1->test_properties()->SetReplicaLayer(
        std::move(grand_child1_replica));
    grand_child1->test_properties()->force_render_surface = true;
  }
  LayerImpl* grand_child1_replica =
      grand_child1->test_properties()->replica_layer;

  // Set up the mask layer on the replica layer
  {
    std::unique_ptr<LayerImpl> replica_mask_layer =
        LayerImpl::Create(host_impl_.active_tree(), 7);
    replica_mask_layer->SetPosition(gfx::PointF());
    // Note: this is not the transform origin being tested.
    replica_mask_layer->SetBounds(grand_child1->bounds());
    grand_child1_replica->test_properties()->SetMaskLayer(
        std::move(replica_mask_layer));
  }
  LayerImpl* replica_mask_layer =
      grand_child1_replica->test_properties()->mask_layer;

  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check that the appropriate render surfaces were created
  ASSERT_TRUE(grand_child1->render_surface());

  // A property change on the replica_mask should damage the reflected region on
  // the target surface.
  ClearDamageForAllSurfaces(root);
  replica_mask_layer->NoteLayerPropertyChanged();

  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  gfx::Rect child_damage_rect =
      child1->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(206, 200, 6, 8).ToString(), child_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, DamageWhenAddedExternally) {
  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];

  // Case 1: This test ensures that when the tracker is given damage, that
  //         it is included with any other partial damage.
  //
  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(10, 11, 12, 13));
  root->render_surface()->damage_tracker()->AddDamageNextUpdate(
      gfx::Rect(15, 16, 32, 33));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::UnionRects(gfx::Rect(15, 16, 32, 33),
                            gfx::Rect(100 + 10, 100 + 11, 12, 13)).ToString(),
            root_damage_rect.ToString());

  // Case 2: An additional sanity check that adding damage works even when
  //         nothing on the layer tree changed.
  //
  ClearDamageForAllSurfaces(root);
  root->render_surface()->damage_tracker()->AddDamageNextUpdate(
      gfx::Rect(30, 31, 14, 15));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(30, 31, 14, 15).ToString(), root_damage_rect.ToString());
}

TEST_F(DamageTrackerTest, VerifyDamageForEmptyLayerList) {
  // Though it should never happen, its a good idea to verify that the damage
  // tracker does not crash when it receives an empty layer_list.

  std::unique_ptr<LayerImpl> root =
      LayerImpl::Create(host_impl_.active_tree(), 1);
  root->test_properties()->force_render_surface = true;
  host_impl_.active_tree()->SetRootLayerForTesting(std::move(root));
  LayerImpl* root_ptr = host_impl_.active_tree()->root_layer_for_testing();
  root_ptr->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root_ptr);

  DCHECK_EQ(root_ptr->render_surface(), root_ptr->render_target());
  RenderSurfaceImpl* target_surface = root_ptr->render_surface();

  LayerImplList empty_list;
  target_surface->damage_tracker()->UpdateDamageTrackingState(
      empty_list, target_surface, false, gfx::Rect(), NULL, FilterOperations());

  gfx::Rect damage_rect =
      target_surface->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(damage_rect.IsEmpty());
}

TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) {
  // If damage is not cleared, it should accumulate.

  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
  LayerImpl* child = root->test_properties()->children[0];

  ClearDamageForAllSurfaces(root);
  child->SetUpdateRect(gfx::Rect(10.f, 11.f, 1.f, 2.f));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);

  // Sanity check damage after the first frame; this isnt the actual test yet.
  gfx::Rect root_damage_rect =
      root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(110, 111, 1, 2).ToString(), root_damage_rect.ToString());

  // New damage, without having cleared the previous damage, should be unioned
  // to the previous one.
  child->SetUpdateRect(gfx::Rect(20, 25, 1, 2));
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_EQ(gfx::Rect(110, 111, 11, 16).ToString(),
            root_damage_rect.ToString());

  // If we notify the damage tracker that we drew the damaged area, then damage
  // should be emptied.
  root->render_surface()->damage_tracker()->DidDrawDamagedArea();
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(root_damage_rect.IsEmpty());

  // Damage should remain empty even after one frame, since there's yet no new
  // damage.
  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
  EmulateDrawingOneFrame(root);
  root_damage_rect =
          root->render_surface()->damage_tracker()->current_damage_rect();
  EXPECT_TRUE(root_damage_rect.IsEmpty());
}

TEST_F(DamageTrackerTest, HugeDamageRect) {
  // This number is so large that we start losting floating point accuracy.
  const int kBigNumber = 900000000;
  // Walk over a range to find floating point inaccuracy boundaries that move
  // toward the wrong direction.
  const int kRange = 5000;

  for (int i = 0; i < kRange; ++i) {
    LayerImpl* root = CreateTestTreeWithOneSurface();
    LayerImpl* child = root->test_properties()->children[0];

    gfx::Transform transform;
    transform.Translate(-kBigNumber, -kBigNumber);

    // The child layer covers (0, 0, i, i) of the viewport,
    // but has a huge negative position.
    child->SetPosition(gfx::PointF());
    child->SetBounds(gfx::Size(kBigNumber + i, kBigNumber + i));
    child->SetTransform(transform);
    root->layer_tree_impl()->property_trees()->needs_rebuild = true;
    EmulateDrawingOneFrame(root);

    // The expected damage should cover the visible part of the child layer,
    // which is (0, 0, i, i) in the viewport.
    gfx::Rect root_damage_rect =
        root->render_surface()->damage_tracker()->current_damage_rect();
    gfx::Rect damage_we_care_about = gfx::Rect(i, i);
    EXPECT_LE(damage_we_care_about.right(), root_damage_rect.right());
    EXPECT_LE(damage_we_care_about.bottom(), root_damage_rect.bottom());
  }
}

}  // namespace
}  // namespace cc


A total 39 firearms and 10kg of gunpowder were found during a police purge on weapons.
They were found at an address in Salisbury Road, Walmer, on March 22.
Although there was a licence for the firearms this was revoked due to licensing conditions not being met.
These were among 300 weapons that have been seized by police cracking down on knife crime and associated offences.
The seizures have been made by proactive patrols across the county since March 11.
In addition more than £100,000 of suspected criminal money and more than 500 wraps of suspected class A drugs have been seized.
Kent Police's assistant chief constable Rob Fordham said: 'This continued period of enforcement activity sends out a very clear message that we have zero tolerance for people who choose to carry a knife in our county.
'Those who do choose to carry a weapon are endangering themselves and innocent members of the public. We will use every power available to us to remove these items from the street."
More than 200 knives were also handed in to Kent Police by a second hand shop in Maidstone.
Their surrender means the items can be safely destroyed and prevents them getting into criminal hands.
Investigating officers have already charged numerous people with knife crime related offences.
Among them are Ricky Sims, 24, of Ames Road in Swanscombe, who has been charged with robbery and possessing a bladed article.
This follows a reported robbery at a store in Henderson Drive, Dartford, on March 30.
He has been remanded in custody and was due to appear at Medway Magistrates Court yesterday.
James Harris, 25, of Olive Road in Dartford, has been charged with robbery and possessing an offensive weapon in a public place following a robbery in the town's Princes Road on March30.
He was remanded in custody at Medway Magistrates' Court. He will next appear at Woolwich Crown Court on April 29.
Lewis Shaw, 27, of Essella Road in Ashford, has been charged with attempted murder, two counts of possessing an offensive weapon in a public place, possessing a bladed article, criminal damage and a public order offence following an assault in Faversham on March 16.
He was arrested on March 23 and was remanded in custody to appear at Maidstone Crown Court on 23 April.
A 16-year-old boy from Rochester has been charged with robbery, possessing a bladed article, acquiring criminal property and possessing cannabis following a reported robbery at a newsagent in Darnley Road, Strood, on March 27.
He was remanded in custody by Medway magistrates to appear at Medway Youth Court yesterday.
John Saunders, 29, of Tennyson Avenue in Canterbury, has been charged with robbery, threatening a person with a bladed article, false imprisonment and burglary following a reported robbery at a betting shop in King Street, Gravesend, on March 11.
He was remanded in custody by Medway magistates to appear at Maidstone Crown Court on April 14.
Mr Fordham added: "People in Kent can feel assured that the county remains a safe place and we are taking robust and proactive action to ensure this remains the case.
"Numerous investigations are currently underway following our arrests and it is pleasing to see the success we have had so far."
Councillors are meeting today to discuss whether to set up a committee to tackle the rise in knife crime.


Le Jour de Merci Donnant was first started by a group of Pilgrims (Pélerins) who fled from l'Angleterre before the McCarran Act to found a colony in the New World (le Nouveau Monde) where they could shoot Indians (les Peaux-Rouges) and eat turkey (dinde) to their hearts' content.
They landed at a place called Plymouth (now a famous voiture Américaine) in a wooden sailing ship called the Mayflower (or Fleur de Mai) in 1620. But while the Pélerins were killing the dindes, the Peaux-Rouges were killing the Pelerins, and there were several hard winters ahead for both of them. The only way the Peaux-Rouges helped the Pelerins was when they taught them to grow corn (mais). The reason they did this was because they liked corn with their Pélerins.
In 1623, after another harsh year, the Pélerins' crops were so good that they decided to have a celebration and give thanks because more mais was raised by the Pélerins than Pélerins were killed by Peaux-Rouges.
Happy Thanksgiving, and I wish you and yours all the happiness of the holiday. And recall that it was when the failures of communal farming gave way to individual family farms in 1623 (three years after the original contract from the London Merchant Adventurers Company was issued) that the seeds of freedom were sewn in the New World. And they have blossomed for 386 years. And may they continue to bloom and grow here and in all nations forever.
Thank you for providing that knowledge!
Thank you, also, for your good wishes. I wish you and all my dear gentle readers every blessing of divine guidance and protection, progress, wisdom, knowledge, success, good fortune, health, love and prosperity now and always!
I haven't read the ebook linked therein, but it's on my increasingly long to-do list.
Thanks for posting the delightful Buchwald explanation of Thanksgiving to the "frogs".
May you know the blessings you wished your readers. Please take care.
.-= No Sheeples Here´s last blog ..Reasons To Be Thankful? =-.


A masterfully written account of events lived, forgotten, and remembered and the tangles that result from partial awareness. This memoir reads like a novel, piecing together past events through vivid dialogue and rich description.... The first foreign traveller to visit the Labyrinth in Gortyn was Cristophoro Buondelmonti in 1415. In his work, Description of the Island of Crete, he identifies the caves at Gortyn as the site of the labyrinth.
Next, get your wide-toothed comb and use it with a picking action to loosen and untangle the hair, before combing it out. If the hair is still damp from the spray, let it dry out first. If the hair is still damp from the spray, let it dry out first.
I wonder how many tangles in my life I have tried to undo myself instead of handing them to the Master. Jesus came to set me free, and untangle every knot. When I try to undo the tangles myself I end up creating more of a mess, and get more deeply entwined in my tangles.


At Springer Nature we recognise that providing the most personalised, up-to-date ROI information helps to make your life easier when it comes to assessing which products are most valuable to your portfolio. We offer a range of services to help you inform your purchasing decisions and encourage usage.
With our dedicated account development approach, we support you to get improved insights on your account and your Springer Nature product portfolio.


The National Center on Safe and Supportive Learning Environment hosted a webinar on February 27, 2014 that provided an in-depth review of Guiding Principle #1 as outlined within the Guiding Principles: A Resource Guide for Improving School Climate and Discipline, a key document in the recently released School Discipline Guidance Package. In particular, it walked through each Action Step identified for Principle #1 implementation, including exploring how each are being implemented by an expert panel of practitioners. These content experts brought deep knowledge of the practical realities associated with integrating Principle #1 strategies into current practice.
The Webinar also included a "tracking guide" that allowed participants to complete a short self-assessment aligned with the Action Steps of Guiding Principle #1 and a list of related resources to support effective implementation.


text:
{-# LANGUAGE FlexibleContexts #-}
-- |
-- Module       : Database.HyperDex.Internal.Util.Foreign
-- Copyright    : (c) Aaron Friel 2014
-- License      : BSD-style
-- Maintainer   : mayreply@aaronfriel.com
-- Stability    : unstable
-- Portability  : portable
--

module Database.HyperDex.Internal.Util.Foreign
 ( module Foreign
 , module Foreign.C.Types
 )
 where

-- See Note [Foreign imports]
import Foreign
 ( Storable (sizeOf, alignment, peek, peekByteOff, poke, pokeByteOff)
 , Ptr
 , advancePtr
 , peekArray
 )
import Foreign.C.Types

{- Note [Foreign imports]
~~~~~~~~~~~~~~~~~~~~~~

A minimal set of foreign functions are exported here. A memory safe,
bounds-checked version may be substituted in as a replacement for these.

These re-exports do not inlude any allocation, as all allocation
should be done through the Resource module. See Note [Resource handling]
in Resource.hs.
-}

redpajama_set_name: RedPajamaGithub


text:
Q: How to GET data from MySql server? I am working on a very important project using Arduino Uno and SIM900 GSM Module. Basically I correctly read the ID from an RFID Card(RFID-RC522) and I need to send the ID using an URL to the Host Provider's Database(000webhost) and I need to get the OUTPUT of my query but as you will see a simple change in the code and the output is completely changed.
Here is the code for the PHP file that needs to send the OUTPUT:
<?php
$dbhost = "localhost";
 $dbuser = "*******";
 $dbpass = "*******";
 $db = "********";
 $conn = new mysqli($dbhost, $dbuser, $dbpass,$db);
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
mysqli_select_db($conn,$db);
date_default_timezone_set('Europe/Rome');
$date = date("Y-m-d G:i:s");
$code=$_REQUEST['code'];

$sql_u = "SELECT * FROM users WHERE code='$code'";
$res_u = mysqli_query($conn, $sql_u);
if (mysqli_num_rows($res_u) > 0)
{
    echo "ALREADY EXISTENT $code";

}
else
{
    $sql = "INSERT INTO users(code,used) VALUES ('$code','$date')";
    if (mysqli_query($conn, $sql)) {
        echo "SUCCESS $code";

    } else {
        echo "ERROR INSERTING $code";

    }
}

mysqli_close($conn);
?>

Anyways, here is the Arduino Code:
#include <SoftwareSerial.h>
#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN 9
#define SS_PIN 10

MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance

SoftwareSerial myGsm(7, 8);

String UID = "";
String pUID;

void setup() {
  Serial.setTimeout(100);
  SPI.begin(); // Init SPI bus
  mfrc522.PCD_Init(); // Init MFRC522

  myGsm.begin(19200);
  Serial.begin(9600);

  myGsm.println("AT+CGATT=1");
  printSerialData();

  myGsm.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
  printSerialData();

  myGsm.println("AT+SAPBR=3,1,\"APN\",\"internet.wind\"");
  printSerialData();

  myGsm.println("AT+SAPBR=2,1");
  printSerialData();

  myGsm.println("AT+SAPBR=1,1");
  printSerialData();

  myGsm.println("AT+HTTPINIT");
  printSerialData();
}

void loop() {
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }
  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }
  pUID = UID;
  UID = mfrc522.PICC_DumpDetailsToSerialUid(&(mfrc522.uid));
  if (UID != pUID) {
    Serial.print("RFID Code: ");
    Serial.print(UID);
    Serial.print("\n");
    String url = "http://mywebsite.000webhostapp.com/test.php?code=", code = "";

    url += UID;
    code = "";
    String httpara = "";
    httpara += "AT+HTTPPARA=\"URL\",";
    httpara += url;
    url = "http://mywebsite.000webhostapp.com/test.php?code=";
    myGsm.println(httpara); // setting the httppara,
    printSerialData();

    myGsm.println("AT+HTTPPARA=\"CID\",1");
    printSerialData();

    myGsm.println("AT+HTTPACTION=0"); //submit the GET request
    //delay(8000);//the delay is important if the return datas are very large, the time required longer.
    printSerialData();

    myGsm.println("AT+HTTPREAD=0,20"); // read the data from the website you access
    //delay(3000);
    printSerialData();

  }

}

void printSerialData() {

  String readI = myGsm.readStringUntil("\r\n");
  Serial.println(readI);
}

The OUTPUT for this code is:
AT+CGATT=1

OK

AT+SAPBR=3,1,"CONTYPE","GPRS"

OK

AT+SAPBR=3,1,"APN","internet.wind"

OK

AT+SAPBR=2,1

+SAPBR: 1,3,"X.X.X.X"

OK

AT+SAPBR=1,1

OK

RFID Code: 172D9B32
AT+HTTPPARA="URL",http://mywebsite.000webhostapp.com/test.php?code=172D9B32

OK

AT+HTTPPARA="CID",1

OK

AT+HTTPACTION=0

OK

AT+HTTPREAD=0,20

OK

If you take a closer look at the last part of the Arduino code, under the line myGsm.println("AT+HTTPACTION=0"); and under the line myGsm.println("AT+HTTPREAD=0,20"); there are some delays that almost all the other SIM900 examples use... I didn't use the delays but with the help from other people, I made it in a way that as soon as the SIM900 has an OUTPUT it just prints it out and eliminating the delay this way. It works fine for all the other commands, but for the last 2 commands it just does something random I think because it should give me the result from the echo of the php file...
NOW look if I enable the two delays:
myGsm.println("AT+HTTPACTION=0"); //submit the GET request
delay(8000);//the delay is important if the return data are very large, the time required longer.
printSerialData();

myGsm.println("AT+HTTPREAD=0,20"); // read the data from the website you access
delay(3000);
printSerialData();

By enabling these 2 line now the OUTPUT is this(correct):
AT+CGATT=1

OK

AT+SAPBR=3,1,"CONTYPE","GPRS"

OK

AT+SAPBR=3,1,"APN","internet.wind"

OK

AT+SAPBR=2,1

+SAPBR: 1,1,"X.X.X.X"

OK

AT+SAPBR=1,1

OK

AT+HTTPINIT

OK

RFID Code: 172D9B32
AT+HTTPPARA="URL",http://mywebsite.000webhostapp.com/test.php?code=172D9B32

OK

AT+HTTPPARA="CID",1

OK

AT+HTTPACTION=0

OK

+HTTPACTION:0,200,16

AT+HTTPREAD=0,20

+HTTPREAD:16
SUCCESS 172D9B32
OK

redpajama_set_name: RedPajamaStackExchange


text:
GLOBAL OPERATIONS CUSTOMER SUPPORT (MNC)
Job Title: GLOBAL OPERATIONS CUSTOMER SUPPORT (MNC)
Location: Bangkok
Human Resources & Office Support
Help Desk/Customer Service
Network Engineer/Administrator
Reference: MNC-EQ-39227
Contact Name: K.Wannisa (Fah)
Contact Email: Wannisa.Khongsook@jac-recruitment.com
Our client is an IT hub to provide, end-to-end service and operations support to commercial banks and other companies in South East Asia and Pacific Ocean areas.
Responsible for Staff rotating 24x7 (8 working hours per shift) Technical Support Line including weekends and public holidays.
Response to user requests and incident/problems via online/phone/email and ticketing log them into service desk application according to establish procedures.
Provide first and single point of contact (SPOC) for global end-users pertaining to new/previously reported IT issues and resolutions to increase productivity.
Provide 1st level technical remote support for applications, common infrastructure, system, network and desktop client.
Provide 1st level technical remote support during the End-of-Day of each bank.
Provide 1st level technical remote support for ATM and other e-Payment equipment.
Bachelor's Degree in Computer Science/Engineering or equivalent experience.
Must possess excellent communication skills in English (both written and oral) to be able to work with international customers (France, India, Laos, Cambodia, Vietnam...).
Min. 2 years' experience working in a shared service environment/ customer support service center supporting medium to large applications in a diverse environment globally.
Min. 2 years' experience providing user support of client applications, PC/Windows network infrastructure, and customer business applications
Basic knowledge on Microsoft Windows XP/2007 workstation/Windows 2008 server and MS office suite (e.g. Outlook, exchange, office etc)
Basic knowledge on Microsoft Active Directory administration, LAN networking, VPN and TCP/IP.
Knowledge on Web Application, Database and Internet concepts and techniques.
Have Linux System Administrator Experiences is preferred.
K.Wannisa (Fah)
THB 20,000 Negotiable
Senior IT Support
THB 25,000 - 35,000 (Depends on Experience)
Junior Middle Web Developer
THB 45,000 - 55,000

redpajama_set_name: RedPajamaCommonCrawl


"But anyone lying to get cheaper motor insurance, or tempted by cheap insurance offers without first checking. of younger.
Car insurance is a necessity for any driver. Besides ensuring financial protection, the insurance provider will also offer legal defense and counseling. However, this service does not come cheap.
Jan 25, 2018. Looking to shop your auto insurance? Here's how to start the process. 6 easy steps to a better, cheaper car insurance policy!
Dec 21, 2017. Why? Because cheap auto insurance policies are great, but purchasing them from unreliable or fickle insurers could wind up being far more.
Here's how to get car, home, travel or pet insurance and cut your costs. Unless you are very fortunate, the chances are th.
Aug 31, 2018. When it comes to finding the cheapest car insurance there are some factors that you can control that will influence your quote. Read on to find.
Related articles Used Cars in Singapore – A Complete Guide to Buying Your First Second-hand Car The Cheapest Car Insurance Po.
You insurance? Compared to 2017, the 2018 study sees annual small car depreciation costs rise from $2,114 to $. compared t.
Get cheap car insurance in Durham NC, Compare best auto insurance rates in Durham and save more than 449$ a year. Call our local Durham number.
While they all walked away, the car was totaled. "In my opinion, taking the cheap route in buying insurance or just going it alone online leaves you open to the risk of either under insuring.


text:
cc.Class({
    extends: cc.Component,

    properties: {
        editBox1: cc.EditBox,
        editBox2: cc.EditBox,
        editBox3: cc.EditBox
    },

    // use this for initialization
    onLoad: function () {

    },

    setFocus: function (event){
        var target = event.target;
        if (target.name === "Button1") {
            this.editBox1.setFocus(true);
        } else if (target.name === "Button2") {
            this.editBox2.setFocus(true);
        } else if (target.name === "Button3"){
            this.editBox3.setFocus(true);
        }

        if (this.editBox1.isFocused()) {
            cc.log("Button1 is focused");
        }
        if (this.editBox2.isFocused()) {
            cc.log("Button2 is focused");
        }
        if (this.editBox3.isFocused()) {
            cc.log("Button3 is focused");
        }
    }

});


text:
Iraq and the Social Impact of War
"Hands of Victory" in Ceremony Square, Baghdad, Iraq during Operation IRAQI FREEDOM - 2003. The hand and arm are modeled after former dictator Saddam Husseins own and surrounded with thousands of Iranian helmets taken from the battlefield. The swords made from the guns of dead Iraqi soldiers. Photo source: Wikipedia
By Peter Hilton, Global Correspondent for Safe World. June 2014.
Women and Children - the Forgotten Victims
Over the past weeks the militant rebel group ISIS (Islamic State in Iraq and the Levant) has been making headlines as they progress through both Syria and Iraq – with Iraqi security forces appearing to offer very little in the way of resistance.
This has sparked debate throughout the Western world about what intervention if any is appropriate to ensure that the democratically elected government in Iraq remains stable, and whether it should even be viewed as the responsibility of the West to intervene in such matters at all.
This all comes in light of discussion between nations about the possibility of launching air strikes against ISIS troops as the Iraqi government has requested in order to help them retain control of the region. The ISIS group have captured the largest oil reserve in Iraq and are progressing steadily towards Baghdad.
However, in light of the escalating international responses, what is often forgotten are the most vulnerable individuals - the women and children who have suffered from seemingly endless conflicts in this war-torn region.
Decades of Conflict
This most recent 'civil war' in Iraq is just one of many conflicts which have blighted the region, with the ISIS troops presenting but one occupying force proceeded by the US, UN, and Iranian troops for years before this, in addition to the rule and remilitarisation of the country by Saddam Hussein.
In recent history, there have been many conflicts beginning with the Iran/Iraq war which raged throughout the 1980s and resulted in massive civilian casualties many of whom died from poison gas attacks in the Northern Kurdish region of Iraq.
This was followed by the Gulf War, which resulted from the Iraqi invasion of Kuwait and UN declarations decrying this action, which were followed by massive aerial bombardment of Iraq by the US and an Iraqi surrender. This course of action appears very similar to that proposed by many spectators, with President Obama recently announcing that he would overrule Congress on any decision to offer military intervention.
The proposition of air strikes once again being used in Iraq is a troubling one; estimates on civilian casualties from airstrikes in the first Gulf War vary but are thought to be between 2,000-3,500. The Gulf War was followed by the Iraq War of 2003, which is one of the most divisive modern conflicts with colossal moral implications and shortcomings; it is widely believed to have been an illegal conflict without valid justification. Furthermore, throughout all of these struggles there has been an ongoing sectarian struggle between Sunni and Shi'ite Muslim groups.
Reuters estimate that over 100,000 people have been killed in bombings, violence and even beheadings perpetrated by a variety of different groups, which has escalated to such an extent that both groups believe they are acting in retaliation to past atrocities carried out by the other.
This kind of death toll from violence within Iraq has had a huge impact on women and children who are left widowed or with injured husbands unable to support or care for themselves.
The US-led invasion of Iraq beginning in 2003 has led to a humanitarian crisis in the region which has seen over a third of the Iraqi population fall into extreme poverty and almost 100 people killed daily before this most recent conflict began. Almost four million people became displaced following the Iraq war with women and children making up the majority of this group.
There have also been increasing worries about women's rights following the conflict, as although the economy has improved with the new democratic system many feel that attitudes towards women have become increasingly reactionary.
One Iraqi woman interviewed by the BBC states:
"Women used to behave in a more liberal way under Saddam. And I hate to say that, because I hate Saddam so much, but women were freer under Saddam".
One in Ten Women Widowed
This highlights an increasing problem as in a country where divorce is heavily frowned upon and over 30 years of conflicts have left millions widowed unable to act independently due to restrictive social customs on women, thousands of women have been left severely disadvantaged. It is estimated that, during the past 30 years, 1.5 million women have been left as widows in Iraq, which represents an enormous 10% of the female population, with many having to resort to living in specially devised camps for widows.
It is clear that humanitarian efforts are failing women in Iraq.
For those who are able to gain employment there is often little respite: two million women in Iraq are the sole earners within their family either as a result of their husband's injuries or of simply being widowed, and often earn wages woefully insufficient to support their families. Though Saddam Hussein's atrocities were many, one consequence of the war and the overthrow of his dictatorship was that a monthly benefit paid to widows was ended, and has not been reinstated by the new government.
There were also rewards for members of the military who married widows, which although not an ideal solution, did help to award some respite to the poverty endured by many women and children who had suffered throughout the many conflicts in Iraq.
Widespread Corruption
The new government has instigated bereavement payments between $3000-4000 – depending on whether the individual killed worked for the government, in addition to a monthly benefit of $85 plus $13 per child; however, for many this is simply not enough to provide adequate accommodation, food, and other costs of living.
Furthermore, there have been increasing complaints that the heavily bureaucratic system through which these benefits are claimed faces issues of massive corruption, with many who should be entitled to government aid failing to apply for the grants as a result.
Poverty, Prostitution and Exploitation
There have been further social costs for women and families in Iraq as a result of ongoing conflict, such as the thousands of women who have found themselves without homes, husbands and means of financial support, leaving them with only one option to support themselves and their families: prostitution.
Women who find themselves are often exploited by ruthless pimps who are rarely prosecuted, whilst many find themselves serving repeated jail sentences of three to four months simply to be forced to return to prostitution upon release.
Conflict only fuels the increasing exploitation of women in this manner as not only are more women left vulnerable by the loss of their husbands, but sadly it is often the occupying forces that are found to be paying the prostitutes in the first place.
The Human Cost of War
When speaking of the social implications of war and the catastrophic effects intervention in Iraq has had upon families, it is far too easy to forget the impact this can have on soldier's families from the intervening nations. Many have died in conflicts within Iraq leaving divided families on several conflicts. In the last conflict within Iraq. roughly 4.500 US troops were killed, 318 from the coalition nations and over 100,000 Iraqi deaths as a direct result of the conflict.
All of these deaths have a huge impact on families, and need to be considered carefully before any further intervention is suggested.
Learning from the Past
In the light of potential new conflicts it is important to remember the impact of those in the past, especially with reference to the colossal implications placed upon innocent civilians within Iraq. It will also be necessary to reflect on the need for some form of intervention as increasingly sectarian dispute between Sunni and Shi'ite Muslim groups grow increasingly wide spread and violent.
Though the progress of ISIS is certainly a troubling prospect, it is paramount that any future intervention by outside forces within the country learns from past mistakes and that a long-term plan is implemented to secure the safety and security of women and children within Iraq.
Global Policy Forum
Narges Mohammadi - Women Human Rights Defenders Are Heroes, Not Criminals
Narges Mohammadi: On Trial in Iran for Defending Human Rights
Discussing Gender Equality, Stereotypes, and Violence Against Women in Israel
Filmmaker Mina Keshavarz Explores Economic Status of Rural Women in Iran
SOS Syrian Children - Helping Those Still in Syria
Illegal and Prolonged Confinement of Bahareh Hedayat, Iranian Human Rights Advocate
Egypt: Azza Soliman, CEWLA Founder, Faces Judicial Harassment


Description: Avail affordable moving services at AMJ Campbell, Canada. They provide hassle free services for packing home furniture and goods and take care of everything from beginning to the end. People moving abroad too can benefit from the services of these excellent, professional home movers.


Best Inspiring Good morning Quotes messagesImages Inspirational was posted in August 25 2018 at 10:53 am and has been seen by 8 users. If you want to view image in full size just click image on gallery bellow.
Good Morning Saying Picture 24 The Best Collection of Quotes 24 Beautiful Inspirational Good Morning Messages Inspirational Good Morning Message Have a positive approach As you Download Free Inspirational Good Morning Quotes Images The Quotes Land Best Inspiring Good morning Quotes messagesImages Inspirational Good Morning Videos Inspirational Good Morning Video message for Good Morning Quotes Say to yourself every morning Inspirational 24 Inspirational Good Morning Quotes With HD Images Good Morning Fun Inspirational Good Morning Quotes Plus Uplifting Good Morning Images Fresh Inspirational Good Morning Quotes for the Day Get on the Positive Inspirational Good Morning Quotes.


OPI Gelcolor A Good Man Darin is Hard to Find 15mL GC H47 But you've found it – in this zesty..
OPI Gelcolor A Grape Fit 15mL This rich purple was made for you. ..
OPI GelColor Alpine Snow 15ml A fresh, crisp white. ..
OPI GelColor Amazon ... Amazoff 15ml I'm making the switch to this deep jun..
OPI GelColor Base Coat 15ml One coat provides a gentle fou..
OPI GelColor Bastille My Heart 15ml Make hearts race in this glimmer of ric..
OPI GelColor Big Apple Red 15ml Bright, shiny and ready to take on the world! ..
OPI GelColor Black Cherry Chutney 15ml A deliciously dark black-red. ..
OPI GelColor Black Onyx 15ml Basic black - and basically fabulous! ..
OPI GelColor Bogota Blackberry 15ml A berry deep, dark wine shade. ..
OPI GelColor Bubble Bath 15ml Sweet candy pink. ..
OPI GelColor Cajun Shrimp 15ml A spicy shade of coral ..
OPI GelColor Cant find my czechbook 15ml Pastel I hope you take credit, because I must ..
OPI GelColor Chasing Rainbows 15ml The rainbow glitter off colour dreams. ..
OPI GelColor Color So Hot it Berns 15ml Cozy up to this warm red apres-ski. ..