910e62b5创建于 1月15日历史提交
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/aura/window.h"

#include <limits.h>

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "build/build_config.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/aura/client/visibility_client.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/scoped_window_capture_request.h"
#include "ui/aura/scoped_window_event_targeting_blocker.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/aura_test_utils.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/test/window_test_api.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tracker.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/class_property.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/layer_animator_test_controller.h"
#include "ui/compositor/test/test_layers.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/overlay_transform_utils.h"

DEFINE_UI_CLASS_PROPERTY_TYPE(const char*)

namespace {

enum class DeletionOrder {
  LAYOUT_MANAGER_FIRST,
  PROPERTY_FIRST,
  UNKNOWN,
};

class DeletionTracker {
 public:
  DeletionTracker() {}

  DeletionTracker(const DeletionTracker&) = delete;
  DeletionTracker& operator=(const DeletionTracker&) = delete;

  ~DeletionTracker() {}

  DeletionOrder order() const { return order_; }
  bool property_deleted() const { return property_deleted_; }
  bool layout_manager_deleted() const { return layout_manager_deleted_; }

  void PropertyDeleted() {
    property_deleted_ = true;
    if (order_ == DeletionOrder::UNKNOWN)
      order_ = DeletionOrder::PROPERTY_FIRST;
  }

  void LayoutManagerDeleted() {
    layout_manager_deleted_ = true;
    if (order_ == DeletionOrder::UNKNOWN)
      order_ = DeletionOrder::LAYOUT_MANAGER_FIRST;
  }

 private:
  bool property_deleted_ = false;
  bool layout_manager_deleted_ = false;
  DeletionOrder order_ = DeletionOrder::UNKNOWN;
};

// The helper class to wait for the animation completion and run callbacks.
class LayerTranslationAnimationNotifier : public ui::CompositorObserver {
 public:
  using AnimationCallback =
      base::RepeatingCallback<void(const gfx::Transform&)>;

  LayerTranslationAnimationNotifier(
      ui::Layer* animation_layer,
      const gfx::Transform& initial_transform_,
      const gfx::Transform& target_transform,
      AnimationCallback animation_start_callback,
      AnimationCallback animation_end_callback,
      AnimationCallback animation_progress_callback)
      : animation_layer_(animation_layer),
        initial_transform_(initial_transform_),
        target_transform_(target_transform),
        animation_start_callback_(animation_start_callback),
        animation_end_callback_(animation_end_callback),
        animation_progress_callback_(animation_progress_callback) {
    animation_layer_->GetCompositor()->AddObserver(this);
  }
  LayerTranslationAnimationNotifier(const LayerTranslationAnimationNotifier&) =
      delete;
  LayerTranslationAnimationNotifier& operator=(
      const LayerTranslationAnimationNotifier&) = delete;
  ~LayerTranslationAnimationNotifier() override {
    animation_layer_->GetCompositor()->RemoveObserver(this);
  }

  void WaitForAnimationCompletion() { run_loop_.Run(); }

  // ui::CompositorObserver:
  void OnCompositingDidCommit(ui::Compositor* compositor) override {
    const gfx::Transform current_transform = animation_layer_->transform();
    if (current_transform == initial_transform_) {
      animation_start_callback_.Run(current_transform);
    } else if (current_transform == target_transform_) {
      animation_end_callback_.Run(current_transform);
      run_loop_.Quit();
    } else {
      animation_progress_callback_.Run(current_transform);
    }
  }

 private:
  // The layer to be animated.
  const raw_ptr<ui::Layer> animation_layer_;

  // The initial transform.
  gfx::Transform initial_transform_;

  // The target transform.
  gfx::Transform target_transform_;

  // The callback to run at the start of the animation.
  AnimationCallback animation_start_callback_;

  // The callback to run at the end of the animation.
  AnimationCallback animation_end_callback_;

  // The callback to run during the progress of the animation.
  AnimationCallback animation_progress_callback_;

  base::RunLoop run_loop_;
};

class DeletionTestProperty {
 public:
  explicit DeletionTestProperty(DeletionTracker* tracker) : tracker_(tracker) {}

  DeletionTestProperty(const DeletionTestProperty&) = delete;
  DeletionTestProperty& operator=(const DeletionTestProperty&) = delete;

  ~DeletionTestProperty() { tracker_->PropertyDeleted(); }

 private:
  raw_ptr<DeletionTracker> tracker_;
};

DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(DeletionTestProperty,
                                   kDeletionTestPropertyKey)

}  // namespace

DEFINE_UI_CLASS_PROPERTY_TYPE(DeletionTestProperty*)

namespace aura {
namespace test {
namespace {

class WindowTest : public AuraTestBase {
 public:
  WindowTest() : max_separation_(0) {
  }

  WindowTest(const WindowTest&) = delete;
  WindowTest& operator=(const WindowTest&) = delete;

  void SetUp() override {
    AuraTestBase::SetUp();
    // TODO: there needs to be an easier way to do this.
    max_separation_ = ui::GestureConfiguration::GetInstance()
                          ->max_separation_for_gesture_touches_in_pixels();
    ui::GestureConfiguration::GetInstance()
        ->set_max_separation_for_gesture_touches_in_pixels(0);
  }

  void TearDown() override {
    AuraTestBase::TearDown();
    ui::GestureConfiguration::GetInstance()
        ->set_max_separation_for_gesture_touches_in_pixels(max_separation_);
  }

 private:
  float max_separation_;
};

// Used for verifying destruction methods are invoked.
class DestroyTrackingDelegateImpl : public TestWindowDelegate {
 public:
  DestroyTrackingDelegateImpl()
      : destroying_count_(0),
        destroyed_count_(0),
        in_destroying_(false) {}

  DestroyTrackingDelegateImpl(const DestroyTrackingDelegateImpl&) = delete;
  DestroyTrackingDelegateImpl& operator=(const DestroyTrackingDelegateImpl&) =
      delete;

  void clear_destroying_count() { destroying_count_ = 0; }
  int destroying_count() const { return destroying_count_; }

  void clear_destroyed_count() { destroyed_count_ = 0; }
  int destroyed_count() const { return destroyed_count_; }

  bool in_destroying() const { return in_destroying_; }

  void OnWindowDestroying(Window* window) override {
    EXPECT_FALSE(in_destroying_);
    in_destroying_ = true;
    destroying_count_++;
  }

  void OnWindowDestroyed(Window* window) override {
    EXPECT_TRUE(in_destroying_);
    in_destroying_ = false;
    destroyed_count_++;
  }

 private:
  int destroying_count_;
  int destroyed_count_;
  bool in_destroying_;
};

// Used to verify that when OnWindowDestroying is invoked the parent is also
// is in the process of being destroyed.
class ChildWindowDelegateImpl : public DestroyTrackingDelegateImpl {
 public:
  explicit ChildWindowDelegateImpl(
      DestroyTrackingDelegateImpl* parent_delegate)
      : parent_delegate_(parent_delegate) {
  }

  ChildWindowDelegateImpl(const ChildWindowDelegateImpl&) = delete;
  ChildWindowDelegateImpl& operator=(const ChildWindowDelegateImpl&) = delete;

  void OnWindowDestroying(Window* window) override {
    EXPECT_TRUE(parent_delegate_->in_destroying());
    DestroyTrackingDelegateImpl::OnWindowDestroying(window);
  }

 private:
  raw_ptr<DestroyTrackingDelegateImpl> parent_delegate_;
};

// Used to verify that a Window is removed from its parent when
// OnWindowDestroyed is called.
class DestroyOrphanDelegate : public TestWindowDelegate {
 public:
  DestroyOrphanDelegate() : window_(nullptr) {}

  DestroyOrphanDelegate(const DestroyOrphanDelegate&) = delete;
  DestroyOrphanDelegate& operator=(const DestroyOrphanDelegate&) = delete;

  void set_window(Window* window) { window_ = window; }

  void OnWindowDestroyed(Window* window) override {
    EXPECT_FALSE(window_->parent());
    window_ = nullptr;
  }

 private:
  raw_ptr<Window> window_;
};

// Used in verifying mouse capture.
class CaptureWindowDelegateImpl : public TestWindowDelegate {
 public:
  CaptureWindowDelegateImpl() {
    ResetCounts();
  }

  CaptureWindowDelegateImpl(const CaptureWindowDelegateImpl&) = delete;
  CaptureWindowDelegateImpl& operator=(const CaptureWindowDelegateImpl&) =
      delete;

  void ResetCounts() {
    capture_changed_event_count_ = 0;
    capture_lost_count_ = 0;
    mouse_event_count_ = 0;
    touch_event_count_ = 0;
    gesture_event_count_ = 0;
  }

  int capture_changed_event_count() const {
    return capture_changed_event_count_;
  }
  int capture_lost_count() const { return capture_lost_count_; }
  int mouse_event_count() const { return mouse_event_count_; }
  int touch_event_count() const { return touch_event_count_; }
  int gesture_event_count() const { return gesture_event_count_; }

  void OnMouseEvent(ui::MouseEvent* event) override {
    if (event->type() == ui::EventType::kMouseCaptureChanged) {
      capture_changed_event_count_++;
    }
    mouse_event_count_++;
  }
  void OnTouchEvent(ui::TouchEvent* event) override { touch_event_count_++; }
  void OnGestureEvent(ui::GestureEvent* event) override {
    gesture_event_count_++;
  }
  void OnCaptureLost() override { capture_lost_count_++; }

 private:
  int capture_changed_event_count_;
  int capture_lost_count_;
  int mouse_event_count_;
  int touch_event_count_;
  int gesture_event_count_;
};

// Keeps track of the location of the gesture.
class GestureTrackPositionDelegate : public TestWindowDelegate {
 public:
  GestureTrackPositionDelegate() {}

  GestureTrackPositionDelegate(const GestureTrackPositionDelegate&) = delete;
  GestureTrackPositionDelegate& operator=(const GestureTrackPositionDelegate&) =
      delete;

  void OnGestureEvent(ui::GestureEvent* event) override {
    position_ = event->location();
    event->StopPropagation();
  }

  const gfx::Point& position() const { return position_; }

 private:
  gfx::Point position_;
};

base::TimeTicks getTime() {
  return ui::EventTimeForNow();
}

class SelfEventHandlingWindowDelegate : public TestWindowDelegate {
 public:
  SelfEventHandlingWindowDelegate() {}

  SelfEventHandlingWindowDelegate(const SelfEventHandlingWindowDelegate&) =
      delete;
  SelfEventHandlingWindowDelegate& operator=(
      const SelfEventHandlingWindowDelegate&) = delete;

  bool ShouldDescendIntoChildForEventHandling(
      Window* child,
      const gfx::Point& location) override {
    return false;
  }
};

// The delegate deletes itself when the window is being destroyed.
class DestroyWindowDelegate : public TestWindowDelegate {
 public:
  DestroyWindowDelegate() {}

  DestroyWindowDelegate(const DestroyWindowDelegate&) = delete;
  DestroyWindowDelegate& operator=(const DestroyWindowDelegate&) = delete;

 private:
  ~DestroyWindowDelegate() override {}

  // Overridden from WindowDelegate.
  void OnWindowDestroyed(Window* window) override { delete this; }
};

void OffsetBounds(Window* window, int horizontal, int vertical) {
  gfx::Rect bounds = window->bounds();
  bounds.Offset(horizontal, vertical);
  window->SetBounds(bounds);
}

TEST_F(WindowTest, GetChildById) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  std::unique_ptr<Window> w11 = CreateTestWindow(
      {.parent = w1.get(), .bounds = {100, 100}, .window_id = 11});
  std::unique_ptr<Window> w111 = CreateTestWindow(
      {.parent = w11.get(), .bounds = {100, 100}, .window_id = 111});
  std::unique_ptr<Window> w12 = CreateTestWindow(
      {.parent = w1.get(), .bounds = {100, 100}, .window_id = 12});

  EXPECT_FALSE(w1->GetChildById(57));
  EXPECT_EQ(w12.get(), w1->GetChildById(12));
  EXPECT_EQ(w111.get(), w1->GetChildById(111));
}

// Make sure that Window::Contains correctly handles children, grandchildren,
// and not containing NULL or parents.
TEST_F(WindowTest, Contains) {
  Window parent(nullptr);
  parent.Init(ui::LAYER_NOT_DRAWN);
  Window child1(nullptr);
  child1.Init(ui::LAYER_NOT_DRAWN);
  Window child2(nullptr);
  child2.Init(ui::LAYER_NOT_DRAWN);

  parent.AddChild(&child1);
  child1.AddChild(&child2);

  EXPECT_TRUE(parent.Contains(&parent));
  EXPECT_TRUE(parent.Contains(&child1));
  EXPECT_TRUE(parent.Contains(&child2));

  EXPECT_FALSE(parent.Contains(nullptr));
  EXPECT_FALSE(child1.Contains(&parent));
  EXPECT_FALSE(child2.Contains(&child1));
}

TEST_F(WindowTest, ContainsPointInRoot) {
  std::unique_ptr<Window> w = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 10, 5, 5}, .window_id = 1},
      SK_ColorWHITE);
  EXPECT_FALSE(w->ContainsPointInRoot(gfx::Point(9, 9)));
  EXPECT_TRUE(w->ContainsPointInRoot(gfx::Point(10, 10)));
  EXPECT_TRUE(w->ContainsPointInRoot(gfx::Point(14, 14)));
  EXPECT_FALSE(w->ContainsPointInRoot(gfx::Point(15, 15)));
  EXPECT_FALSE(w->ContainsPointInRoot(gfx::Point(20, 20)));
}

TEST_F(WindowTest, ContainsPoint) {
  std::unique_ptr<Window> w = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 10, 5, 5}, .window_id = 1},
      SK_ColorWHITE);
  EXPECT_TRUE(w->ContainsPoint(gfx::Point(0, 0)));
  EXPECT_TRUE(w->ContainsPoint(gfx::Point(4, 4)));
  EXPECT_FALSE(w->ContainsPoint(gfx::Point(5, 5)));
  EXPECT_FALSE(w->ContainsPoint(gfx::Point(10, 10)));
}

TEST_F(WindowTest, MakeWindowCapturable) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  // Initially the window is not capturable.
  EXPECT_FALSE(w1->subtree_capture_id().is_valid());

  // Creating requests makes the window capturable as long as those requests
  // remain alive.
  ScopedWindowCaptureRequest request1 = w1->MakeWindowCapturable();
  EXPECT_TRUE(w1->subtree_capture_id().is_valid());
  EXPECT_EQ(request1.GetCaptureId(), w1->subtree_capture_id());
  EXPECT_EQ(request1.GetCaptureId(), w1->layer()->GetSubtreeCaptureId());

  // A new request does not affect the subtree capture ID.
  const viz::SubtreeCaptureId current_id = w1->subtree_capture_id();
  ScopedWindowCaptureRequest request2 = w1->MakeWindowCapturable();
  EXPECT_EQ(current_id, w1->subtree_capture_id());
  EXPECT_EQ(request1.GetCaptureId(), request2.GetCaptureId());

  // Create a new request, then move an existing request into it. This should
  // invalidate the moved-from request.
  ScopedWindowCaptureRequest request3 = w1->MakeWindowCapturable();
  EXPECT_EQ(current_id, request3.GetCaptureId());
  request3 = std::move(request2);
  EXPECT_FALSE(request2.window());
  EXPECT_FALSE(request2.GetCaptureId().is_valid());
  EXPECT_TRUE(w1->subtree_capture_id().is_valid());

  // Destroying |request2| does nothing.
  auto consume_request = [](ScopedWindowCaptureRequest request) {};
  consume_request(std::move(request2));
  EXPECT_TRUE(w1->subtree_capture_id().is_valid());
  EXPECT_EQ(current_id, w1->subtree_capture_id());

  // Destroying |request1| won't affect the window, it will remain capturable,
  // since |request3| is still alive.
  consume_request(std::move(request1));
  EXPECT_FALSE(request1.window());
  EXPECT_FALSE(request1.GetCaptureId().is_valid());
  EXPECT_TRUE(w1->subtree_capture_id().is_valid());
  EXPECT_EQ(current_id, w1->subtree_capture_id());

  // Once all requests are destroyed, the window no longer has a valid capture
  // ID.
  consume_request(std::move(request3));
  EXPECT_FALSE(w1->subtree_capture_id().is_valid());
  EXPECT_FALSE(w1->layer()->GetSubtreeCaptureId().is_valid());
}

TEST_F(WindowTest, DeletingCapturableWindows) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  // Initially the window is not capturable.
  EXPECT_FALSE(w1->subtree_capture_id().is_valid());

  // Deleting a window with capture requests on them will not result in a use-
  // after-free crash.
  ScopedWindowCaptureRequest request1 = w1->MakeWindowCapturable();
  ScopedWindowCaptureRequest request2 = w1->MakeWindowCapturable();
  EXPECT_TRUE(w1->subtree_capture_id().is_valid());
  w1.reset();
  EXPECT_FALSE(request1.GetCaptureId().is_valid());
  EXPECT_FALSE(request2.GetCaptureId().is_valid());
}

TEST_F(WindowTest, LayerReleasingAndSettingOfCapturableWindow) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  EXPECT_FALSE(w1->subtree_capture_id().is_valid());
  ScopedWindowCaptureRequest request = w1->MakeWindowCapturable();
  EXPECT_TRUE(w1->layer()->GetSubtreeCaptureId().is_valid());

  // Releasing the capturable window's layer (i.e. it's no longer associated
  // with the window) will clear its capture ID. However, the window remains
  // marked as capturable with a valid SubtreeCaptureId even though it has no
  // layer.
  std::unique_ptr<ui::Layer> taken_layer = w1->ReleaseLayer();
  EXPECT_FALSE(w1->layer());
  EXPECT_FALSE(taken_layer->GetSubtreeCaptureId().is_valid());
  EXPECT_TRUE(w1->subtree_capture_id().is_valid());

  // Setting a new layer on the window will set the layer's capture ID.
  auto new_layer = std::make_unique<ui::Layer>();
  taken_layer->parent()->Add(new_layer.get());
  w1->Reset(std::move(new_layer));
  EXPECT_TRUE(w1->layer()->GetSubtreeCaptureId().is_valid());
  EXPECT_EQ(request.GetCaptureId(), w1->layer()->GetSubtreeCaptureId());
}

TEST_F(WindowTest, RecreateLayerOfCapturableWindow) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  EXPECT_FALSE(w1->subtree_capture_id().is_valid());
  ScopedWindowCaptureRequest request = w1->MakeWindowCapturable();
  EXPECT_TRUE(w1->layer()->GetSubtreeCaptureId().is_valid());

  // Recreating the layer of a capturable window will preserve the capture ID
  // on the newly recreated window, and clears it from the old layer.
  const viz::SubtreeCaptureId current_id = w1->subtree_capture_id();
  std::unique_ptr<ui::Layer> old_layer = w1->RecreateLayer();
  EXPECT_FALSE(old_layer->GetSubtreeCaptureId().is_valid());
  EXPECT_EQ(current_id, w1->subtree_capture_id());
  EXPECT_EQ(current_id, w1->layer()->GetSubtreeCaptureId());
}

TEST_F(WindowTest, ConvertPointToWindow) {
  // Window::ConvertPointToWindow is mostly identical to
  // Layer::ConvertPointToLayer, except NULL values for |source| are permitted,
  // in which case the function just returns.
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  gfx::Point reference_point(100, 100);
  gfx::Point test_point = reference_point;
  Window::ConvertPointToTarget(nullptr, w1.get(), &test_point);
  EXPECT_EQ(reference_point, test_point);
}

TEST_F(WindowTest, MoveCursorTo) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 10, 500, 500}, .window_id = 1},
      SK_ColorWHITE);
  std::unique_ptr<Window> w11 = CreateTestWindow(
      {.parent = w1.get(), .bounds = {5, 5, 100, 100}, .window_id = 11},
      SK_ColorGREEN);
  std::unique_ptr<Window> w111 = CreateTestWindow(
      {.parent = w11.get(), .bounds = {5, 5, 75, 75}, .window_id = 111},
      SK_ColorCYAN);
  std::unique_ptr<Window> w1111 = CreateTestWindow(
      {.parent = w111.get(), .bounds = {5, 5, 50, 50}, .window_id = 1111},
      SK_ColorRED);

  Window* root = root_window();
  root->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_EQ("10,10", display::Screen::Get()->GetCursorScreenPoint().ToString());
  w1->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_EQ("20,20", display::Screen::Get()->GetCursorScreenPoint().ToString());
  w11->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_EQ("25,25", display::Screen::Get()->GetCursorScreenPoint().ToString());
  w111->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_EQ("30,30", display::Screen::Get()->GetCursorScreenPoint().ToString());
  w1111->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_EQ("35,35", display::Screen::Get()->GetCursorScreenPoint().ToString());
}

TEST_F(WindowTest, ContainsMouse) {
  std::unique_ptr<Window> w = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 10, 500, 500}, .window_id = 1},
      SK_ColorWHITE);
  w->Show();
  WindowTestApi w_test_api(w.get());
  Window* root = root_window();
  root->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_TRUE(w_test_api.ContainsMouse());
  root->MoveCursorTo(gfx::Point(9, 10));
  EXPECT_FALSE(w_test_api.ContainsMouse());
}

// Tests that the root window gets a valid LocalSurfaceId.
TEST_F(WindowTest, RootWindowHasValidLocalSurfaceId) {
  EXPECT_TRUE(root_window()->GetLocalSurfaceId().is_valid());
}

TEST_F(WindowTest, WindowEmbeddingClientHasValidLocalSurfaceId) {
  std::unique_ptr<Window> window = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 10, 300, 200}, .window_id = 1},
      SK_ColorWHITE);
  test::WindowTestApi(window.get()).DisableFrameSinkRegistration();
  window->SetEmbedFrameSinkId(viz::FrameSinkId(0, 1));
  EXPECT_TRUE(window->GetLocalSurfaceId().is_valid());
}

// Test Window::ConvertPointToWindow() with transform to root_window.
TEST_F(WindowTest, MoveCursorToWithTransformRootWindow) {
  gfx::Transform transform;
  transform.Translate(100.0, 100.0);
  transform =
      transform * OverlayTransformToTransform(
                      gfx::OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90, gfx::SizeF());
  transform.Scale(2.0, 5.0);
  host()->SetRootTransform(transform);
  host()->MoveCursorToLocationInDIP(gfx::Point(10, 10));
#if !BUILDFLAG(IS_WIN)
  // TODO(yoshiki): fix this to build on Windows. See crbug.com/133413.OD
  EXPECT_EQ("50,120", QueryLatestMousePositionRequestInHost(host()).ToString());
#endif
  EXPECT_EQ("10,10", display::Screen::Get()->GetCursorScreenPoint().ToString());
}

// Tests Window::ConvertPointToWindow() with transform to non-root windows.
TEST_F(WindowTest, MoveCursorToWithTransformWindow) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 10, 500, 500}, .window_id = 1},
      SK_ColorWHITE);

  gfx::Transform transform1;
  transform1.Scale(2, 2);
  w1->SetTransform(transform1);
  w1->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_EQ("30,30", display::Screen::Get()->GetCursorScreenPoint().ToString());

  gfx::Transform transform2;
  transform2.Translate(-10, 20);
  w1->SetTransform(transform2);
  w1->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_EQ("10,40", display::Screen::Get()->GetCursorScreenPoint().ToString());

  gfx::Transform transform3;
  transform3 = transform3 *
               OverlayTransformToTransform(
                   gfx::OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90, gfx::SizeF());
  w1->SetTransform(transform3);
  w1->MoveCursorTo(gfx::Point(5, 5));
  EXPECT_EQ("5,15", display::Screen::Get()->GetCursorScreenPoint().ToString());

  gfx::Transform transform4;
  transform4.Translate(100.0, 100.0);
  transform4 = transform4 *
               OverlayTransformToTransform(
                   gfx::OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90, gfx::SizeF());
  transform4.Scale(2.0, 5.0);
  w1->SetTransform(transform4);
  w1->MoveCursorTo(gfx::Point(10, 10));
  EXPECT_EQ("60,130",
            display::Screen::Get()->GetCursorScreenPoint().ToString());
}

// Test Window::ConvertPointToWindow() with complex transforms to both root and
// non-root windows.
// Test Window::ConvertPointToWindow() with transform to root_window.
TEST_F(WindowTest, MoveCursorToWithComplexTransform) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 10, 500, 500}, .window_id = 1},
      SK_ColorWHITE);
  std::unique_ptr<Window> w11 = CreateTestWindow(
      {.parent = w1.get(), .bounds = {5, 5, 100, 100}, .window_id = 11},
      SK_ColorGREEN);
  std::unique_ptr<Window> w111 = CreateTestWindow(
      {.parent = w11.get(), .bounds = {5, 5, 75, 75}, .window_id = 111},
      SK_ColorCYAN);
  std::unique_ptr<Window> w1111 = CreateTestWindow(
      {.parent = w111.get(), .bounds = {5, 5, 50, 50}, .window_id = 1111},
      SK_ColorRED);

  // The root window expects transforms that produce integer rects.
  gfx::Transform root_transform;
  root_transform.Translate(60.0, 70.0);
  root_transform =
      root_transform *
      OverlayTransformToTransform(gfx::OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_270,
                                  gfx::SizeF());
  root_transform.Translate(-50.0, -50.0);
  root_transform.Scale(2.0, 3.0);

  gfx::Transform transform;
  transform.Translate(10.0, 20.0);
  transform.Rotate(10.0);
  transform.Scale(0.3f, 0.5f);
  host()->SetRootTransform(root_transform);
  w1->SetTransform(transform);
  w11->SetTransform(transform);
  w111->SetTransform(transform);
  w1111->SetTransform(transform);

  w1111->MoveCursorTo(gfx::Point(10, 10));

#if !BUILDFLAG(IS_WIN)
  // TODO(yoshiki): fix this to build on Windows. See crbug.com/133413.
  EXPECT_EQ("169,80", QueryLatestMousePositionRequestInHost(host()).ToString());
#endif
  EXPECT_EQ("20,53", display::Screen::Get()->GetCursorScreenPoint().ToString());
}

// Tests that we do not crash when a Window is destroyed by going out of
// scope (as opposed to being explicitly deleted by its WindowDelegate).
TEST_F(WindowTest, NoCrashOnWindowDelete) {
  CaptureWindowDelegateImpl delegate;
  std::unique_ptr<Window> window =
      aura::test::CreateTestWindow({.delegate = &delegate,
                                    .parent = root_window(),
                                    .bounds = {20, 20},
                                    .window_id = 0});
}

TEST_F(WindowTest, GetEventHandlerForPoint) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 10, 500, 500}, .window_id = 1},
      SK_ColorWHITE);
  std::unique_ptr<Window> w11 = CreateTestWindow(
      {.parent = w1.get(), .bounds = {5, 5, 100, 100}, .window_id = 11},
      SK_ColorGREEN);
  std::unique_ptr<Window> w111 = CreateTestWindow(
      {.parent = w11.get(), .bounds = {5, 5, 75, 75}, .window_id = 111},
      SK_ColorCYAN);
  std::unique_ptr<Window> w1111 = CreateTestWindow(
      {.parent = w111.get(), .bounds = {5, 5, 50, 50}, .window_id = 1111},
      SK_ColorRED);
  std::unique_ptr<Window> w12 = CreateTestWindow(
      {.parent = w1.get(), .bounds = {10, 420, 25, 25}, .window_id = 12},
      SK_ColorMAGENTA);
  std::unique_ptr<Window> w121 = CreateTestWindow(
      {.parent = w12.get(), .bounds = {5, 5, 5, 5}, .window_id = 121},
      SK_ColorYELLOW);
  std::unique_ptr<Window> w13 = CreateTestWindow(
      {.parent = w1.get(), .bounds = {5, 470, 50, 50}, .window_id = 13},
      SK_ColorGRAY);

  Window* root = root_window();
  w1->parent()->SetBounds(gfx::Rect(500, 500));
  EXPECT_EQ(nullptr, root->GetEventHandlerForPoint(gfx::Point(5, 5)));
  EXPECT_EQ(w1.get(), root->GetEventHandlerForPoint(gfx::Point(11, 11)));
  EXPECT_EQ(w11.get(), root->GetEventHandlerForPoint(gfx::Point(16, 16)));
  EXPECT_EQ(w111.get(), root->GetEventHandlerForPoint(gfx::Point(21, 21)));
  EXPECT_EQ(w1111.get(), root->GetEventHandlerForPoint(gfx::Point(26, 26)));
  EXPECT_EQ(w12.get(), root->GetEventHandlerForPoint(gfx::Point(21, 431)));
  EXPECT_EQ(w121.get(), root->GetEventHandlerForPoint(gfx::Point(26, 436)));
  EXPECT_EQ(w13.get(), root->GetEventHandlerForPoint(gfx::Point(26, 481)));
}

TEST_F(WindowTest, GetEventHandlerForPointInCornerOfChildBounds) {
  // If our child is flush to our top-left corner it gets events just inside the
  // window edges.
  std::unique_ptr<Window> parent = CreateTestWindow(
      {.parent = root_window(), .bounds = {10, 20, 400, 500}, .window_id = 1},
      SK_ColorWHITE);
  std::unique_ptr<Window> child = CreateTestWindow(
      {.parent = parent.get(), .bounds = {0, 0, 60, 70}, .window_id = 2},
      SK_ColorRED);
  EXPECT_EQ(child.get(), parent->GetEventHandlerForPoint(gfx::Point(0, 0)));
  EXPECT_EQ(child.get(), parent->GetEventHandlerForPoint(gfx::Point(1, 1)));
}

TEST_F(WindowTest, GetEventHandlerForPointWithOverrideDescendingOrder) {
  std::unique_ptr<SelfEventHandlingWindowDelegate> parent_delegate(
      new SelfEventHandlingWindowDelegate);

  std::unique_ptr<Window> parent =
      CreateTestWindow({.delegate = parent_delegate.get(),
                        .parent = root_window(),
                        .bounds = {10, 20, 400, 500},
                        .window_id = 1});
  std::unique_ptr<Window> child = CreateTestWindow(
      {.parent = parent.get(), .bounds = {0, 0, 390, 480}, .window_id = 2},
      SK_ColorRED);

  // We can override ShouldDescendIntoChildForEventHandling to make the parent
  // grab all events.
  EXPECT_EQ(parent.get(), parent->GetEventHandlerForPoint(gfx::Point(0, 0)));
  EXPECT_EQ(parent.get(), parent->GetEventHandlerForPoint(gfx::Point(50, 50)));
}

TEST_F(WindowTest, GetToplevelWindow) {
  const gfx::Rect kBounds(0, 0, 10, 10);
  TestWindowDelegate delegate;

  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  std::unique_ptr<Window> w11 = CreateTestWindow({.delegate = &delegate,
                                                  .parent = w1.get(),
                                                  .bounds = kBounds,
                                                  .window_id = 11});
  std::unique_ptr<Window> w111 = CreateTestWindow(
      {.parent = w11.get(), .bounds = {100, 100}, .window_id = 111});
  std::unique_ptr<Window> w1111 = CreateTestWindow({.delegate = &delegate,
                                                    .parent = w111.get(),
                                                    .bounds = kBounds,
                                                    .window_id = 1111});

  EXPECT_TRUE(root_window()->GetToplevelWindow() == nullptr);
  EXPECT_TRUE(w1->GetToplevelWindow() == nullptr);
  EXPECT_EQ(w11.get(), w11->GetToplevelWindow());
  EXPECT_EQ(w11.get(), w111->GetToplevelWindow());
  EXPECT_EQ(w11.get(), w1111->GetToplevelWindow());
}

class AddedToRootWindowObserver : public WindowObserver {
 public:
  AddedToRootWindowObserver() : called_(false) {}

  AddedToRootWindowObserver(const AddedToRootWindowObserver&) = delete;
  AddedToRootWindowObserver& operator=(const AddedToRootWindowObserver&) =
      delete;

  void OnWindowAddedToRootWindow(Window* window) override { called_ = true; }

  bool called() const { return called_; }

 private:
  bool called_;
};

TEST_F(WindowTest, WindowAddedToRootWindowShouldNotifyChildAndNotParent) {
  AddedToRootWindowObserver parent_observer;
  AddedToRootWindowObserver child_observer;
  std::unique_ptr<Window> parent_window = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  std::unique_ptr<Window> child_window = std::make_unique<Window>(nullptr);
  child_window->Init(ui::LAYER_TEXTURED);
  child_window->Show();

  parent_window->AddObserver(&parent_observer);
  child_window->AddObserver(&child_observer);

  parent_window->AddChild(child_window.get());

  EXPECT_FALSE(parent_observer.called());
  EXPECT_TRUE(child_observer.called());

  parent_window->RemoveObserver(&parent_observer);
  child_window->RemoveObserver(&child_observer);
}

// Various destruction assertions.
TEST_F(WindowTest, DestroyTest) {
  DestroyTrackingDelegateImpl parent_delegate;
  ChildWindowDelegateImpl child_delegate(&parent_delegate);
  {
    std::unique_ptr<Window> parent =
        CreateTestWindow({.delegate = &parent_delegate,
                          .parent = root_window(),
                          .window_id = 0});
    CreateTestWindow({.delegate = &child_delegate,
                      .parent = parent.get(),
                      .window_id = 0})
        .release();
  }
  // Both the parent and child should have been destroyed.
  EXPECT_EQ(1, parent_delegate.destroying_count());
  EXPECT_EQ(1, parent_delegate.destroyed_count());
  EXPECT_EQ(1, child_delegate.destroying_count());
  EXPECT_EQ(1, child_delegate.destroyed_count());
}

// Tests that a window is orphaned before OnWindowDestroyed is called.
TEST_F(WindowTest, OrphanedBeforeOnDestroyed) {
  TestWindowDelegate parent_delegate;
  DestroyOrphanDelegate child_delegate;
  {
    std::unique_ptr<Window> parent =
        aura::test::CreateTestWindow({.delegate = &parent_delegate,
                                      .parent = root_window(),
                                      .bounds = {100, 100}});
    std::unique_ptr<Window> child =
        aura::test::CreateTestWindow({.delegate = &child_delegate,
                                      .parent = parent.get(),
                                      .bounds = {100, 100}});
    child_delegate.set_window(child.get());
  }
}

// Make sure StackChildAtTop moves both the window and layer to the front.
TEST_F(WindowTest, StackChildAtTop) {
  Window parent(nullptr);
  parent.Init(ui::LAYER_NOT_DRAWN);
  Window child1(nullptr);
  child1.Init(ui::LAYER_NOT_DRAWN);
  Window child2(nullptr);
  child2.Init(ui::LAYER_NOT_DRAWN);

  parent.AddChild(&child1);
  parent.AddChild(&child2);
  ASSERT_EQ(2u, parent.children().size());
  EXPECT_EQ(&child1, parent.children()[0]);
  EXPECT_EQ(&child2, parent.children()[1]);
  ASSERT_EQ(2u, parent.layer()->children().size());
  EXPECT_EQ(child1.layer(), parent.layer()->children()[0]);
  EXPECT_EQ(child2.layer(), parent.layer()->children()[1]);

  parent.StackChildAtTop(&child1);
  ASSERT_EQ(2u, parent.children().size());
  EXPECT_EQ(&child1, parent.children()[1]);
  EXPECT_EQ(&child2, parent.children()[0]);
  ASSERT_EQ(2u, parent.layer()->children().size());
  EXPECT_EQ(child1.layer(), parent.layer()->children()[1]);
  EXPECT_EQ(child2.layer(), parent.layer()->children()[0]);
}

// Make sure StackChildBelow works.
TEST_F(WindowTest, StackChildBelow) {
  Window parent(nullptr);
  parent.Init(ui::LAYER_NOT_DRAWN);
  Window child1(nullptr);
  child1.Init(ui::LAYER_NOT_DRAWN);
  child1.SetId(1);
  Window child2(nullptr);
  child2.Init(ui::LAYER_NOT_DRAWN);
  child2.SetId(2);
  Window child3(nullptr);
  child3.Init(ui::LAYER_NOT_DRAWN);
  child3.SetId(3);

  parent.AddChild(&child1);
  parent.AddChild(&child2);
  parent.AddChild(&child3);
  EXPECT_EQ("1 2 3", ChildWindowIDsAsString(&parent));

  parent.StackChildBelow(&child1, &child2);
  EXPECT_EQ("1 2 3", ChildWindowIDsAsString(&parent));

  parent.StackChildBelow(&child2, &child1);
  EXPECT_EQ("2 1 3", ChildWindowIDsAsString(&parent));

  parent.StackChildBelow(&child3, &child2);
  EXPECT_EQ("3 2 1", ChildWindowIDsAsString(&parent));

  parent.StackChildBelow(&child3, &child1);
  EXPECT_EQ("2 3 1", ChildWindowIDsAsString(&parent));
}

// Various assertions for StackChildAbove.
TEST_F(WindowTest, StackChildAbove) {
  Window parent(nullptr);
  parent.Init(ui::LAYER_NOT_DRAWN);
  Window child1(nullptr);
  child1.Init(ui::LAYER_NOT_DRAWN);
  Window child2(nullptr);
  child2.Init(ui::LAYER_NOT_DRAWN);
  Window child3(nullptr);
  child3.Init(ui::LAYER_NOT_DRAWN);

  parent.AddChild(&child1);
  parent.AddChild(&child2);

  // Move 1 in front of 2.
  parent.StackChildAbove(&child1, &child2);
  ASSERT_EQ(2u, parent.children().size());
  EXPECT_EQ(&child2, parent.children()[0]);
  EXPECT_EQ(&child1, parent.children()[1]);
  ASSERT_EQ(2u, parent.layer()->children().size());
  EXPECT_EQ(child2.layer(), parent.layer()->children()[0]);
  EXPECT_EQ(child1.layer(), parent.layer()->children()[1]);

  // Add 3, resulting in order [2, 1, 3], then move 2 in front of 1, resulting
  // in [1, 2, 3].
  parent.AddChild(&child3);
  parent.StackChildAbove(&child2, &child1);
  ASSERT_EQ(3u, parent.children().size());
  EXPECT_EQ(&child1, parent.children()[0]);
  EXPECT_EQ(&child2, parent.children()[1]);
  EXPECT_EQ(&child3, parent.children()[2]);
  ASSERT_EQ(3u, parent.layer()->children().size());
  EXPECT_EQ(child1.layer(), parent.layer()->children()[0]);
  EXPECT_EQ(child2.layer(), parent.layer()->children()[1]);
  EXPECT_EQ(child3.layer(), parent.layer()->children()[2]);

  // Move 1 in front of 3, resulting in [2, 3, 1].
  parent.StackChildAbove(&child1, &child3);
  ASSERT_EQ(3u, parent.children().size());
  EXPECT_EQ(&child2, parent.children()[0]);
  EXPECT_EQ(&child3, parent.children()[1]);
  EXPECT_EQ(&child1, parent.children()[2]);
  ASSERT_EQ(3u, parent.layer()->children().size());
  EXPECT_EQ(child2.layer(), parent.layer()->children()[0]);
  EXPECT_EQ(child3.layer(), parent.layer()->children()[1]);
  EXPECT_EQ(child1.layer(), parent.layer()->children()[2]);

  // Moving 1 in front of 2 should lower it, resulting in [2, 1, 3].
  parent.StackChildAbove(&child1, &child2);
  ASSERT_EQ(3u, parent.children().size());
  EXPECT_EQ(&child2, parent.children()[0]);
  EXPECT_EQ(&child1, parent.children()[1]);
  EXPECT_EQ(&child3, parent.children()[2]);
  ASSERT_EQ(3u, parent.layer()->children().size());
  EXPECT_EQ(child2.layer(), parent.layer()->children()[0]);
  EXPECT_EQ(child1.layer(), parent.layer()->children()[1]);
  EXPECT_EQ(child3.layer(), parent.layer()->children()[2]);
}

// Various capture assertions.
TEST_F(WindowTest, CaptureTests) {
  CaptureWindowDelegateImpl delegate;
  std::unique_ptr<Window> window =
      aura::test::CreateTestWindow({.delegate = &delegate,
                                    .parent = root_window(),
                                    .bounds = {20, 20},
                                    .window_id = 0});
  EXPECT_FALSE(window->HasCapture());

  delegate.ResetCounts();

  // Do a capture.
  window->SetCapture();
  EXPECT_TRUE(window->HasCapture());
  EXPECT_EQ(0, delegate.capture_lost_count());
  EXPECT_EQ(0, delegate.capture_changed_event_count());
  ui::test::EventGenerator generator(root_window(), gfx::Point(50, 50));
  generator.PressLeftButton();
  EXPECT_EQ(1, delegate.mouse_event_count());
  generator.ReleaseLeftButton();

  EXPECT_EQ(2, delegate.mouse_event_count());
  delegate.ResetCounts();

  ui::TouchEvent touchev(ui::EventType::kTouchPressed, gfx::Point(50, 50),
                         getTime(),
                         ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&touchev);
  EXPECT_EQ(1, delegate.touch_event_count());
  delegate.ResetCounts();

  window->ReleaseCapture();
  EXPECT_FALSE(window->HasCapture());
  EXPECT_EQ(1, delegate.capture_lost_count());
  EXPECT_EQ(1, delegate.capture_changed_event_count());
  EXPECT_EQ(1, delegate.mouse_event_count());
  EXPECT_EQ(0, delegate.touch_event_count());

  generator.PressLeftButton();
  EXPECT_EQ(1, delegate.mouse_event_count());

  ui::TouchEvent touchev2(ui::EventType::kTouchPressed, gfx::Point(250, 250),
                          getTime(),
                          ui::PointerDetails(ui::EventPointerType::kTouch, 1));
  DispatchEventUsingWindowDispatcher(&touchev2);
  EXPECT_EQ(0, delegate.touch_event_count());

  // Removing the capture window from parent should reset the capture window
  // in the root window.
  window->SetCapture();
  EXPECT_EQ(window.get(), aura::client::GetCaptureWindow(root_window()));
  window->parent()->RemoveChild(window.get());
  EXPECT_FALSE(window->HasCapture());
  EXPECT_EQ(nullptr, aura::client::GetCaptureWindow(root_window()));
}

TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) {
  CaptureWindowDelegateImpl delegate1;
  std::unique_ptr<Window> w1 = aura::test::CreateTestWindow(
      {.delegate = &delegate1, .parent = root_window(), .bounds = {50, 50}});
  CaptureWindowDelegateImpl delegate2;
  std::unique_ptr<Window> w2 =
      aura::test::CreateTestWindow({.delegate = &delegate2,
                                    .parent = root_window(),
                                    .bounds = {50, 50, 50, 50}});

  // Press on w1.
  ui::TouchEvent press1(ui::EventType::kTouchPressed, gfx::Point(10, 10),
                        getTime(),
                        ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&press1);
  // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
  EXPECT_EQ(2, delegate1.gesture_event_count());
  delegate1.ResetCounts();

  // Capturing to w2 should cause the touch to be canceled.
  w2->SetCapture();
  EXPECT_EQ(1, delegate1.touch_event_count());
  EXPECT_EQ(0, delegate2.touch_event_count());
  delegate1.ResetCounts();
  delegate2.ResetCounts();

  // Events are now untargeted.
  ui::TouchEvent move(ui::EventType::kTouchMoved, gfx::Point(10, 20), getTime(),
                      ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&move);
  EXPECT_EQ(0, delegate1.gesture_event_count());
  EXPECT_EQ(0, delegate1.touch_event_count());
  EXPECT_EQ(0, delegate2.gesture_event_count());
  EXPECT_EQ(0, delegate2.touch_event_count());

  ui::TouchEvent release(ui::EventType::kTouchReleased, gfx::Point(10, 20),
                         getTime(),
                         ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&release);
  EXPECT_EQ(0, delegate1.gesture_event_count());
  EXPECT_EQ(0, delegate2.gesture_event_count());

  // A new press is captured by w2.
  ui::TouchEvent press2(ui::EventType::kTouchPressed, gfx::Point(10, 10),
                        getTime(),
                        ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&press2);
  EXPECT_EQ(0, delegate1.gesture_event_count());
  // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
  EXPECT_EQ(2, delegate2.gesture_event_count());
  delegate1.ResetCounts();
  delegate2.ResetCounts();

  // And releasing capture changes nothing.
  w2->ReleaseCapture();
  EXPECT_EQ(0, delegate1.gesture_event_count());
  EXPECT_EQ(0, delegate1.touch_event_count());
  EXPECT_EQ(0, delegate2.gesture_event_count());
  EXPECT_EQ(0, delegate2.touch_event_count());
}

TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) {
  CaptureWindowDelegateImpl delegate;
  std::unique_ptr<Window> window = aura::test::CreateTestWindow(
      {.delegate = &delegate, .parent = root_window(), .bounds = {50, 50}});
  base::TimeTicks time = getTime();
  const int kTimeDelta = 100;

  ui::TouchEvent press(
      ui::EventType::kTouchPressed, gfx::Point(10, 10), time,
      ui::PointerDetails(ui::EventPointerType::kTouch, 0, 1.0f, 1.0f, 1.0f));
  DispatchEventUsingWindowDispatcher(&press);

  // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
  EXPECT_EQ(2, delegate.gesture_event_count());
  EXPECT_EQ(1, delegate.touch_event_count());
  delegate.ResetCounts();

  window->SetCapture();
  EXPECT_EQ(0, delegate.gesture_event_count());
  EXPECT_EQ(0, delegate.touch_event_count());
  delegate.ResetCounts();

  // On move We will get TOUCH_MOVED, GESTURE_TAP_CANCEL,
  // GESTURE_SCROLL_START and GESTURE_SCROLL_UPDATE.
  time += base::Milliseconds(kTimeDelta);
  ui::TouchEvent move(
      ui::EventType::kTouchMoved, gfx::Point(10, 20), time,
      ui::PointerDetails(ui::EventPointerType::kTouch, 0, 1.0f, 1.0f, 1.0f));
  DispatchEventUsingWindowDispatcher(&move);
  EXPECT_EQ(1, delegate.touch_event_count());
  EXPECT_EQ(3, delegate.gesture_event_count());
  delegate.ResetCounts();

  // Release capture shouldn't change anything.
  window->ReleaseCapture();
  EXPECT_EQ(0, delegate.touch_event_count());
  EXPECT_EQ(0, delegate.gesture_event_count());
  delegate.ResetCounts();

  // On move we still get TOUCH_MOVED and GESTURE_SCROLL_UPDATE.
  time += base::Milliseconds(kTimeDelta);
  ui::TouchEvent move2(ui::EventType::kTouchMoved, gfx::Point(10, 30), time,
                       ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&move2);
  EXPECT_EQ(1, delegate.touch_event_count());
  EXPECT_EQ(1, delegate.gesture_event_count());
  delegate.ResetCounts();

  // And on release we get TOUCH_RELEASED, GESTURE_SCROLL_END, GESTURE_END
  time += base::Milliseconds(kTimeDelta);
  ui::TouchEvent release(ui::EventType::kTouchReleased, gfx::Point(10, 20),
                         time,
                         ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&release);
  EXPECT_EQ(1, delegate.touch_event_count());
  EXPECT_EQ(2, delegate.gesture_event_count());
}

// Assertions around SetCapture() and touch/gestures.
TEST_F(WindowTest, TransferCaptureTouchEvents) {
  // Touch on |w1|.
  CaptureWindowDelegateImpl d1;
  std::unique_ptr<Window> w1 = aura::test::CreateTestWindow(
      {.delegate = &d1, .parent = root_window(), .bounds = {20, 20}});
  ui::TouchEvent p1(ui::EventType::kTouchPressed, gfx::Point(10, 10), getTime(),
                    ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&p1);
  // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
  EXPECT_EQ(1, d1.touch_event_count());
  EXPECT_EQ(2, d1.gesture_event_count());
  d1.ResetCounts();

  // Touch on |w2| with a different id.
  CaptureWindowDelegateImpl d2;
  std::unique_ptr<Window> w2 = aura::test::CreateTestWindow(
      {.delegate = &d2, .parent = root_window(), .bounds = {40, 0, 40, 20}});
  ui::TouchEvent p2(ui::EventType::kTouchPressed, gfx::Point(41, 10), getTime(),
                    ui::PointerDetails(ui::EventPointerType::kTouch, 1));
  DispatchEventUsingWindowDispatcher(&p2);
  EXPECT_EQ(0, d1.touch_event_count());
  EXPECT_EQ(0, d1.gesture_event_count());
  // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN for new target window.
  EXPECT_EQ(1, d2.touch_event_count());
  EXPECT_EQ(2, d2.gesture_event_count());
  d1.ResetCounts();
  d2.ResetCounts();

  // Set capture on |w2|, this should send a cancel (TAP_CANCEL, END) to |w1|
  // but not |w2|.
  w2->SetCapture();
  EXPECT_EQ(1, d1.touch_event_count());
  EXPECT_EQ(2, d1.gesture_event_count());
  EXPECT_EQ(0, d2.touch_event_count());
  EXPECT_EQ(0, d2.gesture_event_count());
  d1.ResetCounts();
  d2.ResetCounts();

  CaptureWindowDelegateImpl d3;
  std::unique_ptr<Window> w3 = aura::test::CreateTestWindow(
      {.delegate = &d3, .parent = root_window(), .bounds = {100, 101}});
  // Set capture on |w3|. All touches have already been cancelled.
  w3->SetCapture();
  EXPECT_EQ(0, d1.touch_event_count());
  EXPECT_EQ(0, d1.gesture_event_count());
  EXPECT_EQ(1, d2.touch_event_count());
  EXPECT_EQ(2, d2.gesture_event_count());
  EXPECT_EQ(0, d3.touch_event_count());
  EXPECT_EQ(0, d3.gesture_event_count());
  d2.ResetCounts();

  // Move touch id originally associated with |w2|. The touch has been
  // cancelled, so no events should be dispatched.
  ui::TouchEvent m3(ui::EventType::kTouchMoved, gfx::Point(110, 105), getTime(),
                    ui::PointerDetails(ui::EventPointerType::kTouch, 1));
  DispatchEventUsingWindowDispatcher(&m3);
  EXPECT_EQ(0, d1.touch_event_count());
  EXPECT_EQ(0, d1.gesture_event_count());
  EXPECT_EQ(0, d2.touch_event_count());
  EXPECT_EQ(0, d2.gesture_event_count());
  EXPECT_EQ(0, d3.touch_event_count());
  EXPECT_EQ(0, d3.gesture_event_count());

  // When we release capture, no touches are canceled.
  w3->ReleaseCapture();
  EXPECT_EQ(0, d1.touch_event_count());
  EXPECT_EQ(0, d1.gesture_event_count());
  EXPECT_EQ(0, d2.touch_event_count());
  EXPECT_EQ(0, d2.gesture_event_count());
  EXPECT_EQ(0, d3.touch_event_count());
  EXPECT_EQ(0, d3.gesture_event_count());

  // The touch has been cancelled, so no events are dispatched.
  ui::TouchEvent m4(ui::EventType::kTouchMoved, gfx::Point(120, 105), getTime(),
                    ui::PointerDetails(ui::EventPointerType::kTouch, 1));
  DispatchEventUsingWindowDispatcher(&m4);
  EXPECT_EQ(0, d1.touch_event_count());
  EXPECT_EQ(0, d1.gesture_event_count());
  EXPECT_EQ(0, d2.touch_event_count());
  EXPECT_EQ(0, d2.gesture_event_count());
  EXPECT_EQ(0, d3.touch_event_count());
  EXPECT_EQ(0, d3.gesture_event_count());
}

// Changes capture while capture is already ongoing.
TEST_F(WindowTest, ChangeCaptureWhileMouseDown) {
  CaptureWindowDelegateImpl delegate;
  std::unique_ptr<Window> window(aura::test::CreateTestWindow(
      {.delegate = &delegate, .parent = root_window(), .bounds = {20, 20}}));
  CaptureWindowDelegateImpl delegate2;
  std::unique_ptr<Window> w2(
      aura::test::CreateTestWindow({.delegate = &delegate2,
                                    .parent = root_window(),
                                    .bounds = {20, 20, 20, 20}}));

  // Execute the scheduled draws so that mouse events are not
  // aggregated.
  RunAllPendingInMessageLoop();

  EXPECT_FALSE(window->HasCapture());

  // Do a capture.
  delegate.ResetCounts();
  window->SetCapture();
  EXPECT_TRUE(window->HasCapture());
  EXPECT_EQ(0, delegate.capture_lost_count());
  EXPECT_EQ(0, delegate.capture_changed_event_count());
  ui::test::EventGenerator generator(root_window(), gfx::Point(50, 50));
  generator.PressLeftButton();
  EXPECT_EQ(0, delegate.capture_lost_count());
  EXPECT_EQ(0, delegate.capture_changed_event_count());
  EXPECT_EQ(1, delegate.mouse_event_count());

  // Set capture to |w2|, should implicitly unset capture for |window|.
  delegate.ResetCounts();
  delegate2.ResetCounts();
  w2->SetCapture();

  generator.MoveMouseTo(gfx::Point(40, 40), 2);
  EXPECT_EQ(1, delegate.capture_lost_count());
  EXPECT_EQ(1, delegate.capture_changed_event_count());
  EXPECT_EQ(1, delegate.mouse_event_count());
  EXPECT_EQ(2, delegate2.mouse_event_count());
}

// Verifies capture is reset when a window is destroyed.
TEST_F(WindowTest, ReleaseCaptureOnDestroy) {
  CaptureWindowDelegateImpl delegate;
  std::unique_ptr<Window> window(aura::test::CreateTestWindow(
      {.delegate = &delegate, .parent = root_window(), .bounds = {20, 20}}));
  EXPECT_FALSE(window->HasCapture());

  // Do a capture.
  window->SetCapture();
  EXPECT_TRUE(window->HasCapture());

  // Destroy the window.
  window.reset();

  // Make sure the root window doesn't reference the window anymore.
  EXPECT_EQ(nullptr, host()->dispatcher()->mouse_pressed_handler());
  EXPECT_EQ(nullptr, aura::client::GetCaptureWindow(root_window()));
}

TEST_F(WindowTest, GetBoundsInRootWindow) {
  std::unique_ptr<Window> viewport(
      CreateTestWindow({.parent = root_window(), .bounds = {300, 300}}));
  std::unique_ptr<Window> child(
      CreateTestWindow({.parent = viewport.get(), .bounds = {100, 100}}));
  // Sanity check.
  EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());

  // The |child| window's screen bounds should move along with the |viewport|.
  viewport->SetBounds(gfx::Rect(-100, -100, 300, 300));
  EXPECT_EQ("-100,-100 100x100", child->GetBoundsInRootWindow().ToString());

  // The |child| window is moved to the 0,0 in screen coordinates.
  // |GetBoundsInRootWindow()| should return 0,0.
  child->SetBounds(gfx::Rect(100, 100, 100, 100));
  EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());
}

TEST_F(WindowTest, GetBoundsInRootWindowWithLayers) {
  std::unique_ptr<Window> viewport =
      CreateTestWindow({.parent = root_window(), .bounds = {300, 300}});

  std::unique_ptr<Window> widget(
      CreateTestWindow({.parent = viewport.get(), .bounds = {200, 200}}));

  std::unique_ptr<Window> child(
      CreateTestWindow({.parent = widget.get(), .bounds = {100, 100}}));

  // Sanity check.
  EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());

  // The |child| window's screen bounds should move along with the |viewport|.
  OffsetBounds(viewport.get(), -100, -100);
  EXPECT_EQ("-100,-100 100x100", child->GetBoundsInRootWindow().ToString());

  OffsetBounds(widget.get(), 50, 50);
  EXPECT_EQ("-50,-50 100x100", child->GetBoundsInRootWindow().ToString());

  // The |child| window is moved to the 0,0 in screen coordinates.
  // |GetBoundsInRootWindow()| should return 0,0.
  OffsetBounds(child.get(), 50, 50);
  EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());
}

TEST_F(WindowTest, GetBoundsInRootWindowWithLayersAndTranslations) {
  std::unique_ptr<Window> viewport(
      CreateTestWindow({.parent = root_window(), .bounds = {300, 300}}));

  std::unique_ptr<Window> widget =
      CreateTestWindow({.parent = viewport.get(), .bounds = {200, 200}});

  std::unique_ptr<Window> child(
      CreateTestWindow({.parent = widget.get(), .bounds = {100, 100}}));

  // Sanity check.
  EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());

  // The |child| window's screen bounds should move along with the |viewport|.
  viewport->SetBounds(gfx::Rect(-100, -100, 300, 300));
  EXPECT_EQ("-100,-100 100x100", child->GetBoundsInRootWindow().ToString());

  widget->SetBounds(gfx::Rect(50, 50, 200, 200));
  EXPECT_EQ("-50,-50 100x100", child->GetBoundsInRootWindow().ToString());

  // The |child| window is moved to the 0,0 in screen coordinates.
  // |GetBoundsInRootWindow()| should return 0,0.
  child->SetBounds(gfx::Rect(50, 50, 100, 100));
  EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());

  gfx::Transform transform1;
  transform1.Translate(-10, 20);
  viewport->SetTransform(transform1);
  EXPECT_EQ("-10,20 100x100", child->GetBoundsInRootWindow().ToString());

  gfx::Transform transform2;
  transform2.Translate(40, 100);
  widget->SetTransform(transform2);
  EXPECT_EQ("30,120 100x100", child->GetBoundsInRootWindow().ToString());

  // Testing potentially buggy place
  gfx::Transform transform3;
  transform3.Translate(-30, -120);
  child->SetTransform(transform3);
  EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());
}

// TODO(tdanderson): Remove this class and use
//                   test::EventCountDelegate in its place.
class MouseEnterExitWindowDelegate : public TestWindowDelegate {
 public:
  MouseEnterExitWindowDelegate() : entered_(false), exited_(false) {}

  MouseEnterExitWindowDelegate(const MouseEnterExitWindowDelegate&) = delete;
  MouseEnterExitWindowDelegate& operator=(const MouseEnterExitWindowDelegate&) =
      delete;

  void OnMouseEvent(ui::MouseEvent* event) override {
    switch (event->type()) {
      case ui::EventType::kMouseEntered:
        EXPECT_TRUE(event->flags() & ui::EF_IS_SYNTHESIZED);
        entered_ = true;
        break;
      case ui::EventType::kMouseExited:
        EXPECT_TRUE(event->flags() & ui::EF_IS_SYNTHESIZED);
        exited_ = true;
        break;
      default:
        break;
    }
  }

  bool entered() const { return entered_; }
  bool exited() const { return exited_; }

  // Clear the entered / exited states.
  void ResetExpectations() {
    entered_ = false;
    exited_ = false;
  }

 private:
  bool entered_;
  bool exited_;
};

// Verifies that the WindowDelegate receives MouseExit and MouseEnter events for
// mouse transitions from window to window.
TEST_F(WindowTest, MouseEnterExit) {
  MouseEnterExitWindowDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 1}));
  MouseEnterExitWindowDelegate d2;
  std::unique_ptr<Window> w2(
      aura::test::CreateTestWindow({.delegate = &d2,
                                    .parent = root_window(),
                                    .bounds = {70, 70, 50, 50},
                                    .window_id = 2}));

  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseToCenterOf(w1.get());
  EXPECT_TRUE(d1.entered());
  EXPECT_FALSE(d1.exited());
  EXPECT_FALSE(d2.entered());
  EXPECT_FALSE(d2.exited());

  generator.MoveMouseToCenterOf(w2.get());
  EXPECT_TRUE(d1.entered());
  EXPECT_TRUE(d1.exited());
  EXPECT_TRUE(d2.entered());
  EXPECT_FALSE(d2.exited());
}

// Verifies that the WindowDelegate receives MouseExit from
// EventType::kMouseExited.
TEST_F(WindowTest, WindowTreeHostExit) {
  MouseEnterExitWindowDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 1}));

  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseToCenterOf(w1.get());
  EXPECT_TRUE(d1.entered());
  EXPECT_FALSE(d1.exited());
  d1.ResetExpectations();

  ui::MouseEvent exit_event(ui::EventType::kMouseExited, gfx::Point(),
                            gfx::Point(), ui::EventTimeForNow(), 0, 0);
  DispatchEventUsingWindowDispatcher(&exit_event);
  EXPECT_FALSE(d1.entered());
  EXPECT_TRUE(d1.exited());
}

// Verifies that the WindowDelegate receives MouseExit and MouseEnter events for
// mouse transitions from window to window, even if the entered window sets
// and releases capture.
TEST_F(WindowTest, MouseEnterExitWithClick) {
  MouseEnterExitWindowDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 1}));
  MouseEnterExitWindowDelegate d2;
  std::unique_ptr<Window> w2(
      aura::test::CreateTestWindow({.delegate = &d2,
                                    .parent = root_window(),
                                    .bounds = {70, 70, 50, 50},
                                    .window_id = 2}));

  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseToCenterOf(w1.get());
  EXPECT_TRUE(d1.entered());
  EXPECT_FALSE(d1.exited());
  EXPECT_FALSE(d2.entered());
  EXPECT_FALSE(d2.exited());

  // Emmulate what Views does on a click by grabbing and releasing capture.
  generator.PressLeftButton();
  w1->SetCapture();
  w1->ReleaseCapture();
  generator.ReleaseLeftButton();

  generator.MoveMouseToCenterOf(w2.get());
  EXPECT_TRUE(d1.entered());
  EXPECT_TRUE(d1.exited());
  EXPECT_TRUE(d2.entered());
  EXPECT_FALSE(d2.exited());
}

TEST_F(WindowTest, MouseEnterExitWhenDeleteWithCapture) {
  MouseEnterExitWindowDelegate delegate;
  std::unique_ptr<Window> window(
      aura::test::CreateTestWindow({.delegate = &delegate,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 1}));

  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseToCenterOf(window.get());
  EXPECT_TRUE(delegate.entered());
  EXPECT_FALSE(delegate.exited());

  // Emmulate what Views does on a click by grabbing and releasing capture.
  generator.PressLeftButton();
  window->SetCapture();

  delegate.ResetExpectations();
  generator.MoveMouseTo(0, 0);
  EXPECT_FALSE(delegate.entered());
  EXPECT_FALSE(delegate.exited());

  delegate.ResetExpectations();
  window.reset();
  EXPECT_FALSE(delegate.entered());
  EXPECT_FALSE(delegate.exited());
}

// Verifies that the correct enter / exits are sent if windows appear and are
// deleted under the current mouse position.
TEST_F(WindowTest, MouseEnterExitWithWindowAppearAndDelete) {
  MouseEnterExitWindowDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 1}));

  // The cursor is moved into the bounds of |w1|. We expect the delegate
  // of |w1| to see an EventType::kMouseEntered event.
  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseToCenterOf(w1.get());
  EXPECT_TRUE(d1.entered());
  EXPECT_FALSE(d1.exited());
  d1.ResetExpectations();

  MouseEnterExitWindowDelegate d2;
  {
    std::unique_ptr<Window> w2(
        aura::test::CreateTestWindow({.delegate = &d2,
                                      .parent = root_window(),
                                      .bounds = {10, 10, 50, 50},
                                      .window_id = 2}));
    // Enters / exits can be sent asynchronously.
    RunAllPendingInMessageLoop();

    // |w2| appears over top of |w1|. We expect the delegate of |w1| to see
    // an EventType::kMouseExited and the delegate of |w2| to see an
    // EventType::kMouseEntered.
    EXPECT_FALSE(d1.entered());
    EXPECT_TRUE(d1.exited());
    EXPECT_TRUE(d2.entered());
    EXPECT_FALSE(d2.exited());
    d1.ResetExpectations();
    d2.ResetExpectations();
  }

  // Enters / exits can be sent asynchronously.
  RunAllPendingInMessageLoop();

  // |w2| has been destroyed, so its delegate should see no further events.
  // The delegate of |w1| should see an EventType::kMouseEntered event.
  EXPECT_TRUE(d1.entered());
  EXPECT_FALSE(d1.exited());
  EXPECT_FALSE(d2.entered());
  EXPECT_FALSE(d2.exited());
}

// Verifies that enter / exits are sent if windows appear and are hidden
// under the current mouse position..
TEST_F(WindowTest, MouseEnterExitWithHide) {
  MouseEnterExitWindowDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 1}));

  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseToCenterOf(w1.get());
  EXPECT_TRUE(d1.entered());
  EXPECT_FALSE(d1.exited());

  MouseEnterExitWindowDelegate d2;
  std::unique_ptr<Window> w2(
      aura::test::CreateTestWindow({.delegate = &d2,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 2}));
  // Enters / exits can be send asynchronously.
  RunAllPendingInMessageLoop();
  EXPECT_TRUE(d1.entered());
  EXPECT_TRUE(d1.exited());
  EXPECT_TRUE(d2.entered());
  EXPECT_FALSE(d2.exited());

  d1.ResetExpectations();
  w2->Hide();
  // Enters / exits can be send asynchronously.
  RunAllPendingInMessageLoop();
  EXPECT_TRUE(d2.exited());
  EXPECT_TRUE(d1.entered());
}

TEST_F(WindowTest, MouseEnterExitWithParentHide) {
  MouseEnterExitWindowDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 1}));
  MouseEnterExitWindowDelegate d2;
  Window* w2 = aura::test::CreateTestWindow({.delegate = &d2,
                                             .parent = w1.get(),
                                             .bounds = {10, 10, 50, 50},
                                             .window_id = 2})
                   .release();
  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseToCenterOf(w2);
  // Enters / exits can be send asynchronously.
  RunAllPendingInMessageLoop();
  EXPECT_TRUE(d2.entered());
  EXPECT_FALSE(d2.exited());

  d2.ResetExpectations();
  w1->Hide();
  RunAllPendingInMessageLoop();
  EXPECT_FALSE(d2.entered());
  EXPECT_TRUE(d2.exited());

  w1.reset();
}

TEST_F(WindowTest, MouseEnterExitWithParentDelete) {
  MouseEnterExitWindowDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {10, 10, 50, 50},
                                    .window_id = 1}));
  MouseEnterExitWindowDelegate d2;
  Window* w2 = aura::test::CreateTestWindow({.delegate = &d2,
                                             .parent = w1.get(),
                                             .bounds = {10, 10, 50, 50},
                                             .window_id = 2})
                   .release();
  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseToCenterOf(w2);

  // Enters / exits can be send asynchronously.
  RunAllPendingInMessageLoop();
  EXPECT_TRUE(d2.entered());
  EXPECT_FALSE(d2.exited());

  d2.ResetExpectations();
  w1.reset();
  RunAllPendingInMessageLoop();

  // Both windows are in the process of destroying, so their delegates should
  // not see any mouse events.
  EXPECT_FALSE(d1.entered());
  EXPECT_FALSE(d1.exited());
  EXPECT_FALSE(d2.entered());
  EXPECT_FALSE(d2.exited());
}

// Creates a window with a delegate (w111) that can handle events at a lower
// z-index than a window without a delegate (w12). w12 is sized to fill the
// entire bounds of the container. This test verifies that
// GetEventHandlerForPoint() skips w12 even though its bounds contain the event,
// because it has no children that can handle the event and it has no delegate
// allowing it to handle the event itself.
TEST_F(WindowTest, GetEventHandlerForPoint_NoDelegate) {
  TestWindowDelegate d111;
  std::unique_ptr<Window> w1(aura::test::CreateTestWindow(
      {.parent = root_window(), .bounds = {500, 500}, .window_id = 1}));
  std::unique_ptr<Window> w11(aura::test::CreateTestWindow(
      {.parent = w1.get(), .bounds = {500, 500}, .window_id = 11}));
  std::unique_ptr<Window> w111(
      aura::test::CreateTestWindow({.delegate = &d111,
                                    .parent = w11.get(),
                                    .bounds = {50, 50, 450, 450},
                                    .window_id = 111}));
  std::unique_ptr<Window> w12(aura::test::CreateTestWindow(
      {.parent = w1.get(), .bounds = {500, 500}, .window_id = 12}));

  gfx::Point target_point = w111->bounds().CenterPoint();
  EXPECT_EQ(w111.get(), w1->GetEventHandlerForPoint(target_point));
}

class VisibilityWindowDelegate : public TestWindowDelegate {
 public:
  VisibilityWindowDelegate()
      : shown_(0),
        hidden_(0) {
  }

  VisibilityWindowDelegate(const VisibilityWindowDelegate&) = delete;
  VisibilityWindowDelegate& operator=(const VisibilityWindowDelegate&) = delete;

  int shown() const { return shown_; }
  int hidden() const { return hidden_; }
  void Clear() {
    shown_ = 0;
    hidden_ = 0;
  }

  void OnWindowTargetVisibilityChanged(bool visible) override {
    if (visible)
      shown_++;
    else
      hidden_++;
  }

 private:
  int shown_;
  int hidden_;
};

// Verifies show/hide propagate correctly to children and the layer.
TEST_F(WindowTest, Visibility) {
  VisibilityWindowDelegate d;
  VisibilityWindowDelegate d2;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d,
                                    .parent = root_window(),
                                    .bounds = {100, 100},
                                    .window_id = 1}));
  std::unique_ptr<Window> w2(aura::test::CreateTestWindow({.delegate = &d2,
                                                           .parent = w1.get(),
                                                           .bounds = {100, 100},
                                                           .window_id = 2}));
  std::unique_ptr<Window> w3(CreateTestWindow(
      {.parent = w2.get(), .bounds = {100, 100}, .window_id = 3}));

  // Create shows all the windows.
  EXPECT_TRUE(w1->IsVisible());
  EXPECT_TRUE(w2->IsVisible());
  EXPECT_TRUE(w3->IsVisible());
  EXPECT_EQ(1, d.shown());

  d.Clear();
  w1->Hide();
  EXPECT_FALSE(w1->IsVisible());
  EXPECT_FALSE(w2->IsVisible());
  EXPECT_FALSE(w3->IsVisible());
  EXPECT_EQ(1, d.hidden());
  EXPECT_EQ(0, d.shown());

  w2->Show();
  EXPECT_FALSE(w1->IsVisible());
  EXPECT_FALSE(w2->IsVisible());
  EXPECT_FALSE(w3->IsVisible());

  w3->Hide();
  EXPECT_FALSE(w1->IsVisible());
  EXPECT_FALSE(w2->IsVisible());
  EXPECT_FALSE(w3->IsVisible());

  d.Clear();
  w1->Show();
  EXPECT_TRUE(w1->IsVisible());
  EXPECT_TRUE(w2->IsVisible());
  EXPECT_FALSE(w3->IsVisible());
  EXPECT_EQ(0, d.hidden());
  EXPECT_EQ(1, d.shown());

  w3->Show();
  EXPECT_TRUE(w1->IsVisible());
  EXPECT_TRUE(w2->IsVisible());
  EXPECT_TRUE(w3->IsVisible());

  // Verify that if an ancestor isn't visible and we change the visibility of a
  // child window that OnChildWindowVisibilityChanged() is still invoked.
  w1->Hide();
  d2.Clear();
  w2->Hide();
  EXPECT_EQ(1, d2.hidden());
  EXPECT_EQ(0, d2.shown());
  d2.Clear();
  w2->Show();
  EXPECT_EQ(0, d2.hidden());
  EXPECT_EQ(1, d2.shown());
}

TEST_F(WindowTest, EventTargetingPolicy) {
  TestWindowDelegate d11;
  TestWindowDelegate d12;
  TestWindowDelegate d111;
  TestWindowDelegate d121;
  std::unique_ptr<Window> w1(aura::test::CreateTestWindow(
      {.parent = root_window(), .bounds = {500, 500}, .window_id = 1}));
  std::unique_ptr<Window> w11(
      aura::test::CreateTestWindow({.delegate = &d11,
                                    .parent = w1.get(),
                                    .bounds = {500, 500},
                                    .window_id = 11}));
  std::unique_ptr<Window> w111(
      aura::test::CreateTestWindow({.delegate = &d111,
                                    .parent = w11.get(),
                                    .bounds = {50, 50, 450, 450},
                                    .window_id = 111}));
  std::unique_ptr<Window> w12(
      aura::test::CreateTestWindow({.delegate = &d12,
                                    .parent = w1.get(),
                                    .bounds = {500, 500},
                                    .window_id = 12}));
  std::unique_ptr<Window> w121(
      aura::test::CreateTestWindow({.delegate = &d121,
                                    .parent = w12.get(),
                                    .bounds = {150, 150, 50, 50},
                                    .window_id = 121}));

  EXPECT_EQ(w121.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
  w12->SetEventTargetingPolicy(EventTargetingPolicy::kTargetOnly);
  EXPECT_EQ(w12.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
  EXPECT_TRUE(w12.get()->layer()->accept_events());
  w12->SetEventTargetingPolicy(EventTargetingPolicy::kTargetAndDescendants);
  EXPECT_EQ(w12.get(), w1->GetEventHandlerForPoint(gfx::Point(10, 10)));
  EXPECT_TRUE(w12.get()->layer()->accept_events());
  w12->SetEventTargetingPolicy(EventTargetingPolicy::kNone);
  EXPECT_EQ(w11.get(), w1->GetEventHandlerForPoint(gfx::Point(10, 10)));
  EXPECT_FALSE(w12.get()->layer()->accept_events());

  w12->SetEventTargetingPolicy(EventTargetingPolicy::kTargetAndDescendants);

  EXPECT_EQ(w121.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
  w121->SetEventTargetingPolicy(EventTargetingPolicy::kNone);
  EXPECT_EQ(w12.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
  EXPECT_FALSE(w121.get()->layer()->accept_events());
  w12->SetEventTargetingPolicy(EventTargetingPolicy::kNone);
  EXPECT_EQ(w111.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
  EXPECT_FALSE(w12.get()->layer()->accept_events());
  w111->SetEventTargetingPolicy(EventTargetingPolicy::kNone);
  EXPECT_EQ(w11.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
  EXPECT_FALSE(w111.get()->layer()->accept_events());

  w11->SetEventTargetingPolicy(EventTargetingPolicy::kDescendantsOnly);
  EXPECT_EQ(nullptr, w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
  EXPECT_TRUE(w11.get()->layer()->accept_events());

  w111->SetEventTargetingPolicy(EventTargetingPolicy::kTargetAndDescendants);
  EXPECT_EQ(w111.get(), w1->GetEventHandlerForPoint(gfx::Point(160, 160)));
  EXPECT_TRUE(w111.get()->layer()->accept_events());
}

TEST_F(WindowTest, ScopedEventTargetingBlockerTest) {
  // Test only when all event targeting blockers are removed from the window,
  // its event targeting policy will restore back to its original value.
  std::unique_ptr<Window> window(aura::test::CreateTestWindow(
      {.parent = root_window(), .bounds = {500, 500}, .window_id = 1}));
  EXPECT_EQ(window->event_targeting_policy(),
            EventTargetingPolicy::kTargetAndDescendants);
  auto event_targeting_blocker1 =
      std::make_unique<ScopedWindowEventTargetingBlocker>(window.get());
  EXPECT_EQ(window->event_targeting_policy(), EventTargetingPolicy::kNone);
  auto event_targeting_blocker2 =
      std::make_unique<ScopedWindowEventTargetingBlocker>(window.get());
  EXPECT_EQ(window->event_targeting_policy(), EventTargetingPolicy::kNone);
  event_targeting_blocker2.reset();
  EXPECT_EQ(window->event_targeting_policy(), EventTargetingPolicy::kNone);
  event_targeting_blocker1.reset();
  EXPECT_EQ(window->event_targeting_policy(),
            EventTargetingPolicy::kTargetAndDescendants);

  // It's possible that the event target policy changes when there is an event
  // targeting blocker in place. In this case when the event targeting blocker
  // is removed from the window, the window should restore to the changed event
  // targeting policy.
  auto event_targeting_blocker3 =
      std::make_unique<ScopedWindowEventTargetingBlocker>(window.get());
  EXPECT_EQ(window->event_targeting_policy(), EventTargetingPolicy::kNone);
  window->SetEventTargetingPolicy(EventTargetingPolicy::kTargetOnly);
  EXPECT_EQ(window->event_targeting_policy(), EventTargetingPolicy::kNone);
  event_targeting_blocker3.reset();
  EXPECT_EQ(window->event_targeting_policy(),
            EventTargetingPolicy::kTargetOnly);
}

// Tests transformation on the root window.
TEST_F(WindowTest, Transform) {
  gfx::Size size = host()->GetBoundsInPixels().size();
  EXPECT_EQ(
      gfx::Rect(size),
      display::Screen::Get()->GetDisplayNearestPoint(gfx::Point()).bounds());

  // Rotate it clock-wise 90 degrees.
  host()->SetRootTransform(OverlayTransformToTransform(
      gfx::OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90, gfx::SizeF(size)));

  // The size should be the transformed size.
  gfx::Size transformed_size(size.height(), size.width());
  EXPECT_EQ(transformed_size.ToString(),
            root_window()->bounds().size().ToString());
  EXPECT_EQ(gfx::Rect(transformed_size).ToString(),
            display::Screen::Get()
                ->GetDisplayNearestPoint(gfx::Point())
                .bounds()
                .ToString());

  // Host size shouldn't change.
  EXPECT_EQ(size.ToString(), host()->GetBoundsInPixels().size().ToString());
}

TEST_F(WindowTest, TransformGesture) {
  gfx::Size size = host()->GetBoundsInPixels().size();

  std::unique_ptr<GestureTrackPositionDelegate> delegate(
      new GestureTrackPositionDelegate);
  std::unique_ptr<Window> window(
      aura::test::CreateTestWindow({.delegate = delegate.get(),
                                    .parent = root_window(),
                                    .bounds = {20, 20},
                                    .window_id = -1234}));

  // Rotate the root-window clock-wise 90 degrees.
  host()->SetRootTransform(OverlayTransformToTransform(
      gfx::OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90, gfx::SizeF(size)));

  ui::TouchEvent press(ui::EventType::kTouchPressed,
                       gfx::Point(size.height() - 10, 10), getTime(),
                       ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  DispatchEventUsingWindowDispatcher(&press);
  EXPECT_EQ(gfx::Point(10, 10).ToString(), delegate->position().ToString());
}

TEST_F(WindowTest, Property) {
  std::unique_ptr<Window> w(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 0}));

  static const char native_prop_key[] = "fnord";

  // Non-existent properties should return the default values.
  EXPECT_EQ(nullptr, w->GetNativeWindowProperty(native_prop_key));

  w->SetNativeWindowProperty(native_prop_key, &*w);
  EXPECT_EQ(&*w, w->GetNativeWindowProperty(native_prop_key));
  w->SetNativeWindowProperty(native_prop_key, nullptr);
  EXPECT_EQ(nullptr, w->GetNativeWindowProperty(native_prop_key));
}

class DeletionTestLayoutManager : public LayoutManager {
 public:
  explicit DeletionTestLayoutManager(DeletionTracker* tracker)
      : tracker_(tracker) {}

  DeletionTestLayoutManager(const DeletionTestLayoutManager&) = delete;
  DeletionTestLayoutManager& operator=(const DeletionTestLayoutManager&) =
      delete;

  ~DeletionTestLayoutManager() override { tracker_->LayoutManagerDeleted(); }

 private:
  // LayoutManager:
  void OnWindowResized() override {}
  void OnWindowAddedToLayout(Window* child) override {}
  void OnWillRemoveWindowFromLayout(Window* child) override {}
  void OnWindowRemovedFromLayout(Window* child) override {}
  void OnChildWindowVisibilityChanged(Window* child, bool visible) override {}
  void SetChildBounds(Window* child,
                      const gfx::Rect& requested_bounds) override {}

  raw_ptr<DeletionTracker> tracker_;
};

TEST_F(WindowTest, DeleteLayoutManagerBeforeOwnedProps) {
  DeletionTracker tracker;
  {
    Window w(nullptr);
    w.Init(ui::LAYER_NOT_DRAWN);
    w.SetLayoutManager(std::make_unique<DeletionTestLayoutManager>(&tracker));
    w.SetProperty(kDeletionTestPropertyKey,
                  std::make_unique<DeletionTestProperty>(&tracker));
  }
  EXPECT_TRUE(tracker.property_deleted());
  EXPECT_TRUE(tracker.layout_manager_deleted());
  EXPECT_EQ(DeletionOrder::LAYOUT_MANAGER_FIRST, tracker.order());
}

TEST_F(WindowTest, SetBoundsInternalShouldCheckTargetBounds) {
  // We cannot short-circuit animations in this test.
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);

  std::unique_ptr<Window> w1(
      CreateTestWindow({.parent = root_window(), .bounds = {100, 100}}));

  EXPECT_TRUE(w1->layer());
  w1->layer()->GetAnimator()->set_disable_timer_for_test(true);
  ui::LayerAnimator* animator = w1->layer()->GetAnimator();

  EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
  EXPECT_EQ("0,0 100x100", w1->layer()->GetTargetBounds().ToString());

  // Animate to a different position.
  {
    ui::ScopedLayerAnimationSettings settings(w1->layer()->GetAnimator());
    w1->SetBounds(gfx::Rect(100, 100, 100, 100));
  }

  EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
  EXPECT_EQ("100,100 100x100", w1->layer()->GetTargetBounds().ToString());

  // Animate back to the first position. The animation hasn't started yet, so
  // the current bounds are still (0, 0, 100, 100), but the target bounds are
  // (100, 100, 100, 100). If we step the animator ahead, we should find that
  // we're at (0, 0, 100, 100). That is, the second animation should be applied.
  {
    ui::ScopedLayerAnimationSettings settings(w1->layer()->GetAnimator());
    w1->SetBounds(gfx::Rect(0, 0, 100, 100));
  }

  EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
  EXPECT_EQ("0,0 100x100", w1->layer()->GetTargetBounds().ToString());

  // Confirm that the target bounds are reached.
  base::TimeTicks start_time =
      w1->layer()->GetAnimator()->last_step_time();

  animator->Step(start_time + base::Milliseconds(1000));

  EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
}

typedef std::pair<const void*, intptr_t> PropertyChangeInfo;

class WindowObserverTest : public WindowTest,
                           public WindowObserver {
 public:
  struct VisibilityInfo {
    bool window_visible;
    bool visible_param;
    int changed_count;
  };

  struct WindowBoundsInfo {
    int changed_count = 0;
    raw_ptr<Window> window = nullptr;
    gfx::Rect old_bounds;
    gfx::Rect new_bounds;
    ui::PropertyChangeReason reason =
        ui::PropertyChangeReason::NOT_FROM_ANIMATION;
  };

  struct WindowOpacityInfo {
    int changed_count = 0;
    raw_ptr<Window> window = nullptr;
    ui::PropertyChangeReason reason =
        ui::PropertyChangeReason::NOT_FROM_ANIMATION;
  };

  struct WindowTargetTransformChangingInfo {
    int changed_count = 0;
    raw_ptr<Window> window = nullptr;
    gfx::Transform new_transform;
  };

  struct WindowTransformedInfo {
    int changed_count = 0;
    raw_ptr<Window> window = nullptr;
    ui::PropertyChangeReason reason =
        ui::PropertyChangeReason::NOT_FROM_ANIMATION;
  };

  struct CountAndWindow {
    int count = 0;
    raw_ptr<Window> window = nullptr;
  };

  WindowObserverTest() = default;

  WindowObserverTest(const WindowObserverTest&) = delete;
  WindowObserverTest& operator=(const WindowObserverTest&) = delete;

  ~WindowObserverTest() override = default;

  const VisibilityInfo* GetVisibilityInfo() const {
    return visibility_info_.get();
  }

  const WindowBoundsInfo& window_bounds_info() const {
    return window_bounds_info_;
  }

  const WindowOpacityInfo& window_opacity_info() const {
    return window_opacity_info_;
  }

  const CountAndWindow& alpha_shape_info() const { return alpha_shape_info_; }

  const WindowTargetTransformChangingInfo&
  window_target_transform_changing_info() const {
    return window_target_transform_changing_info_;
  }

  const WindowTransformedInfo& window_transformed_info() const {
    return window_transformed_info_;
  }

  const CountAndWindow& layer_recreated_info() const {
    return layer_recreated_info_;
  }

  void ResetVisibilityInfo() {
    visibility_info_.reset();
  }

  // Returns a description of the WindowObserver methods that have been invoked.
  std::string WindowObserverCountStateAndClear() {
    std::string result(base::StringPrintf("added=%d removing=%d removed=%d",
                                          added_count_, removing_count_,
                                          removed_count_));
    added_count_ = removing_count_ = removed_count_ = 0;
    return result;
  }

  int DestroyedCountAndClear() {
    int result = destroyed_count_;
    destroyed_count_ = 0;
    return result;
  }

  // Return a tuple of the arguments passed in OnPropertyChanged callback.
  PropertyChangeInfo PropertyChangeInfoAndClear() {
    PropertyChangeInfo result(property_key_, old_property_value_);
    property_key_ = nullptr;
    old_property_value_ = -3;
    return result;
  }

 private:
  void OnWindowAdded(Window* new_window) override { added_count_++; }

  void OnWillRemoveWindow(Window* window) override { removing_count_++; }

  void OnWindowRemoved(Window* removed_window) override { removed_count_++; }

  void OnWindowVisibilityChanged(Window* window, bool visible) override {
    if (!visibility_info_) {
      visibility_info_ = std::make_unique<VisibilityInfo>();
      visibility_info_->changed_count = 0;
    }
    visibility_info_->window_visible = window->IsVisible();
    visibility_info_->visible_param = visible;
    visibility_info_->changed_count++;
  }

  void OnWindowDestroyed(Window* window) override {
    EXPECT_FALSE(window->parent());
    destroyed_count_++;

    // Reset notification data to avoid dangling pointers to the Window.
    window_bounds_info_ = {};
    window_opacity_info_ = {};
    window_target_transform_changing_info_ = {};
    window_transformed_info_ = {};
    alpha_shape_info_ = {};
    layer_recreated_info_ = {};
  }

  void OnWindowPropertyChanged(Window* window,
                               const void* key,
                               intptr_t old) override {
    property_key_ = key;
    old_property_value_ = old;
  }

  void OnWindowBoundsChanged(Window* window,
                             const gfx::Rect& old_bounds,
                             const gfx::Rect& new_bounds,
                             ui::PropertyChangeReason reason) override {
    ++window_bounds_info_.changed_count;
    window_bounds_info_.window = window;
    window_bounds_info_.old_bounds = old_bounds;
    window_bounds_info_.new_bounds = new_bounds;
    window_bounds_info_.reason = reason;
  }

  void OnWindowOpacitySet(Window* window,
                          ui::PropertyChangeReason reason) override {
    ++window_opacity_info_.changed_count;
    window_opacity_info_.window = window;
    window_opacity_info_.reason = reason;
  }

  void OnWindowAlphaShapeSet(Window* window) override {
    ++alpha_shape_info_.count;
    alpha_shape_info_.window = window;
  }

  void OnWindowTargetTransformChanging(
      Window* window,
      const gfx::Transform& new_transform) override {
    ++window_target_transform_changing_info_.changed_count;
    window_target_transform_changing_info_.window = window;
    window_target_transform_changing_info_.new_transform = new_transform;
  }

  void OnWindowTransformed(Window* window,
                           ui::PropertyChangeReason reason) override {
    ++window_transformed_info_.changed_count;
    window_transformed_info_.window = window;
    window_transformed_info_.reason = reason;
  }

  void OnWindowLayerRecreated(Window* window) override {
    ++layer_recreated_info_.count;
    layer_recreated_info_.window = window;
  }

  int added_count_ = 0;
  int removing_count_ = 0;
  int removed_count_ = 0;
  int destroyed_count_ = 0;
  std::unique_ptr<VisibilityInfo> visibility_info_;
  raw_ptr<const void> property_key_ = nullptr;
  intptr_t old_property_value_ = -3;
  std::vector<std::pair<int, int> > transform_notifications_;
  WindowBoundsInfo window_bounds_info_;
  WindowOpacityInfo window_opacity_info_;
  WindowTargetTransformChangingInfo window_target_transform_changing_info_;
  WindowTransformedInfo window_transformed_info_;
  CountAndWindow alpha_shape_info_;
  CountAndWindow layer_recreated_info_;
};

// Various assertions for WindowObserver.
TEST_F(WindowObserverTest, WindowObserver) {
  std::unique_ptr<Window> w1 = CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1});
  w1->AddObserver(this);

  // Create a new window as a child of w1, our observer should be notified.
  std::unique_ptr<Window> w2(CreateTestWindow(
      {.parent = w1.get(), .bounds = {100, 100}, .window_id = 2}));
  EXPECT_EQ("added=1 removing=0 removed=0", WindowObserverCountStateAndClear());

  // Delete w2, which should result in the remove notifications.
  w2.reset();
  EXPECT_EQ("added=0 removing=1 removed=1", WindowObserverCountStateAndClear());

  // Create a window that isn't parented to w1, we shouldn't get any
  // notification.
  std::unique_ptr<Window> w3(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 3}));
  EXPECT_EQ("added=0 removing=0 removed=0", WindowObserverCountStateAndClear());

  // Similarly destroying w3 shouldn't notify us either.
  w3.reset();
  EXPECT_EQ("added=0 removing=0 removed=0", WindowObserverCountStateAndClear());
  w1->RemoveObserver(this);
}

// Test if OnWindowVisibilityChanged is invoked with expected
// parameters.
TEST_F(WindowObserverTest, WindowVisibility) {
  std::unique_ptr<Window> w1(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  std::unique_ptr<Window> w2(CreateTestWindow(
      {.parent = w1.get(), .bounds = {100, 100}, .window_id = 1}));
  w2->AddObserver(this);

  // Hide should make the window invisible and the passed visible
  // parameter is false.
  w2->Hide();
  EXPECT_TRUE(GetVisibilityInfo());
  EXPECT_TRUE(GetVisibilityInfo());
  if (!GetVisibilityInfo())
    return;
  EXPECT_FALSE(GetVisibilityInfo()->window_visible);
  EXPECT_FALSE(GetVisibilityInfo()->visible_param);
  EXPECT_EQ(1, GetVisibilityInfo()->changed_count);

  // If parent isn't visible, showing window won't make the window visible, but
  // passed visible value must be true.
  w1->Hide();
  ResetVisibilityInfo();
  EXPECT_TRUE(!GetVisibilityInfo());
  w2->Show();
  EXPECT_TRUE(GetVisibilityInfo());
  if (!GetVisibilityInfo())
    return;
  EXPECT_FALSE(GetVisibilityInfo()->window_visible);
  EXPECT_TRUE(GetVisibilityInfo()->visible_param);
  EXPECT_EQ(1, GetVisibilityInfo()->changed_count);

  // If parent is visible, showing window will make the window
  // visible and the passed visible value is true.
  w1->Show();
  w2->Hide();
  ResetVisibilityInfo();
  w2->Show();
  EXPECT_TRUE(GetVisibilityInfo());
  if (!GetVisibilityInfo())
    return;
  EXPECT_TRUE(GetVisibilityInfo()->window_visible);
  EXPECT_TRUE(GetVisibilityInfo()->visible_param);
  EXPECT_EQ(1, GetVisibilityInfo()->changed_count);

  // Verify that the OnWindowVisibilityChanged only once
  // per visibility change.
  w2->Hide();
  EXPECT_EQ(2, GetVisibilityInfo()->changed_count);

  w2->Hide();
  EXPECT_EQ(2, GetVisibilityInfo()->changed_count);
}

// Test if OnWindowDestroyed is invoked as expected.
TEST_F(WindowObserverTest, WindowDestroyed) {
  // Delete a window should fire a destroyed notification.
  std::unique_ptr<Window> w1(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  w1->AddObserver(this);
  w1.reset();
  EXPECT_EQ(1, DestroyedCountAndClear());

  // Observe on child and delete parent window should fire a notification.
  std::unique_ptr<Window> parent(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  Window* child =
      CreateTestWindow(
          {.parent = parent.get(), .bounds = {100, 100}, .window_id = 1})
          .release();  // owned by parent
  child->AddObserver(this);
  parent.reset();
  EXPECT_EQ(1, DestroyedCountAndClear());
}

TEST_F(WindowObserverTest, PropertyChanged) {
  // Setting property should fire a property change notification.
  std::unique_ptr<Window> w1(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  w1->AddObserver(this);

  static const WindowProperty<int> prop = {-2};
  static const char native_prop_key[] = "fnord";

  w1->SetProperty(&prop, 1);
  EXPECT_EQ(PropertyChangeInfo(&prop, -2), PropertyChangeInfoAndClear());
  w1->SetProperty(&prop, -2);
  EXPECT_EQ(PropertyChangeInfo(&prop, 1), PropertyChangeInfoAndClear());
  w1->SetProperty(&prop, 3);
  EXPECT_EQ(PropertyChangeInfo(&prop, -2), PropertyChangeInfoAndClear());
  w1->ClearProperty(&prop);
  EXPECT_EQ(PropertyChangeInfo(&prop, 3), PropertyChangeInfoAndClear());

  w1->SetNativeWindowProperty(native_prop_key, &*w1);
  EXPECT_EQ(PropertyChangeInfo(native_prop_key, 0),
            PropertyChangeInfoAndClear());
  w1->SetNativeWindowProperty(native_prop_key, nullptr);
  EXPECT_EQ(PropertyChangeInfo(native_prop_key,
                               reinterpret_cast<intptr_t>(&*w1)),
            PropertyChangeInfoAndClear());

  // Sanity check to see if |PropertyChangeInfoAndClear| really clears.
  EXPECT_EQ(PropertyChangeInfo(nullptr, -3), PropertyChangeInfoAndClear());
}

// Verify that WindowObserver::OnWindowBoundsChanged() is notified when the
// bounds of a Window's Layer change without an animation.
TEST_F(WindowObserverTest, WindowBoundsChanged) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  window->AddObserver(this);
  const gfx::Rect initial_bounds = window->bounds();
  constexpr gfx::Rect kTargetBounds(10, 20, 30, 40);
  window->layer()->SetBounds(kTargetBounds);
  ASSERT_EQ(1, window_bounds_info().changed_count);
  EXPECT_EQ(window.get(), window_bounds_info().window);
  EXPECT_EQ(initial_bounds, window_bounds_info().old_bounds);
  EXPECT_EQ(kTargetBounds, window_bounds_info().new_bounds);
  EXPECT_EQ(ui::PropertyChangeReason::NOT_FROM_ANIMATION,
            window_bounds_info().reason);
}

// Verify that WindowObserver::OnWindowBoundsChanged() is notified at every step
// of a bounds animation.
TEST_F(WindowObserverTest, WindowBoundsChangedAnimation) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  window->AddObserver(this);
  const gfx::Rect initial_bounds = window->bounds();
  constexpr gfx::Rect kTargetBounds(10, 20, 30, 40);
  const gfx::Rect step_bounds =
      gfx::Tween::RectValueBetween(0.5, initial_bounds, kTargetBounds);

  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
  window->layer()->SetBounds(kTargetBounds);
  ASSERT_EQ(0, window_opacity_info().changed_count);

  window->layer()->GetAnimator()->Step(
      window->layer()->GetAnimator()->last_step_time() +
      settings.GetTransitionDuration() / 2);
  ASSERT_EQ(1, window_bounds_info().changed_count);
  EXPECT_EQ(window.get(), window_bounds_info().window);
  EXPECT_EQ(initial_bounds, window_bounds_info().old_bounds);
  EXPECT_EQ(step_bounds, window_bounds_info().new_bounds);
  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
            window_bounds_info().reason);

  window->layer()->GetAnimator()->StopAnimatingProperty(
      ui::LayerAnimationElement::BOUNDS);
  ASSERT_EQ(2, window_bounds_info().changed_count);
  EXPECT_EQ(window.get(), window_bounds_info().window);
  EXPECT_EQ(step_bounds, window_bounds_info().old_bounds);
  EXPECT_EQ(kTargetBounds, window_bounds_info().new_bounds);
  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
            window_bounds_info().reason);
}

// Verify that WindowObserver::OnWindowOpacitySet() is notified when the
// opacity of a Window's Layer changes without an animation.
TEST_F(WindowObserverTest, WindowOpacityChanged) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  window->AddObserver(this);
  window->layer()->SetOpacity(0.5f);
  ASSERT_EQ(1, window_opacity_info().changed_count);
  EXPECT_EQ(window.get(), window_opacity_info().window);
  EXPECT_EQ(ui::PropertyChangeReason::NOT_FROM_ANIMATION,
            window_opacity_info().reason);
}

// Verify that WindowObserver::OnWindowOpacitySet() is notified at the
// beginning and at the end of a threaded opacity animation.
TEST_F(WindowObserverTest, WindowOpacityChangedAnimation) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  window->AddObserver(this);

  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
  window->layer()->SetOpacity(0.5f);
  ASSERT_EQ(1, window_opacity_info().changed_count);
  EXPECT_EQ(window.get(), window_opacity_info().window);
  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
            window_opacity_info().reason);

  window->layer()->GetAnimator()->StopAnimatingProperty(
      ui::LayerAnimationElement::OPACITY);
  ASSERT_EQ(2, window_opacity_info().changed_count);
  EXPECT_EQ(window.get(), window_opacity_info().window);
  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
            window_opacity_info().reason);
}

// Verify that WindowObserver::OnWindowAlphaShapeSet() is notified when an alpha
// shape is set for a window.
TEST_F(WindowObserverTest, WindowAlphaShapeChanged) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  window->AddObserver(this);

  auto shape = std::make_unique<ui::Layer::ShapeRects>();
  shape->emplace_back(0, 0, 10, 20);

  EXPECT_EQ(0, alpha_shape_info().count);
  EXPECT_EQ(nullptr, alpha_shape_info().window.get());
  window->layer()->SetAlphaShape(std::move(shape));
  EXPECT_EQ(1, alpha_shape_info().count);
  EXPECT_EQ(window.get(), alpha_shape_info().window);
}

// Verify that WindowObserver::OnWindow(TargetTransformChanging|Transformed)()
// are notified when SetTransform() is called and there is no animation.
TEST_F(WindowObserverTest, SetTransform) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  window->AddObserver(this);
  gfx::Transform target_transform;
  target_transform.Skew(10.0, 5.0);
  window->SetTransform(target_transform);

  ASSERT_EQ(1, window_target_transform_changing_info().changed_count);
  EXPECT_EQ(window.get(), window_target_transform_changing_info().window);
  EXPECT_EQ(target_transform,
            window_target_transform_changing_info().new_transform);

  ASSERT_EQ(1, window_transformed_info().changed_count);
  EXPECT_EQ(window.get(), window_transformed_info().window);
  EXPECT_EQ(ui::PropertyChangeReason::NOT_FROM_ANIMATION,
            window_transformed_info().reason);
}

// Verify that WindowObserver::OnWindowTransformed)() is notified at the
// beginning and at the end of a threaded transform animation. Verify that
// WindowObserver::OnWindowTargetTransformChanging() is notified when the
// threaded animation is started by SetTransform().
TEST_F(WindowObserverTest, SetTransformAnimation) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  window->AddObserver(this);

  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
  gfx::Transform target_transform;
  target_transform.Skew(10.0, 5.0);
  window->SetTransform(target_transform);

  ASSERT_EQ(1, window_target_transform_changing_info().changed_count);
  EXPECT_EQ(window.get(), window_target_transform_changing_info().window);
  EXPECT_EQ(target_transform,
            window_target_transform_changing_info().new_transform);

  ASSERT_EQ(0, window_transformed_info().changed_count);

  window->layer()->GetAnimator()->StopAnimatingProperty(
      ui::LayerAnimationElement::TRANSFORM);

  EXPECT_EQ(1, window_target_transform_changing_info().changed_count);

  ASSERT_EQ(1, window_transformed_info().changed_count);
  EXPECT_EQ(window.get(), window_transformed_info().window);
  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
            window_transformed_info().reason);
}

TEST_F(WindowObserverTest, OnWindowLayerRecreated) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  window->AddObserver(this);

  EXPECT_EQ(0, layer_recreated_info().count);
  std::unique_ptr<ui::Layer> old_layer = window->RecreateLayer();
  EXPECT_EQ(1, layer_recreated_info().count);
  EXPECT_EQ(window.get(), layer_recreated_info().window);
}

TEST_F(WindowObserverTest, OnWindowLayerRecreatedWithOpacityAnimation) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));

  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
  window->layer()->SetOpacity(0.5);
  EXPECT_TRUE(window->layer()->GetAnimator()->IsAnimatingProperty(
      ui::LayerAnimationElement::OPACITY));

  window->AddObserver(this);

  EXPECT_EQ(0, layer_recreated_info().count);
  EXPECT_EQ(0, window_opacity_info().changed_count);
  std::unique_ptr<ui::Layer> old_layer = window->RecreateLayer();
  EXPECT_EQ(1, layer_recreated_info().count);
  EXPECT_EQ(window.get(), layer_recreated_info().window);
  EXPECT_EQ(1, window_opacity_info().changed_count);
  EXPECT_EQ(window.get(), window_opacity_info().window);
  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
            window_opacity_info().reason);
}

TEST_F(WindowObserverTest, OnWindowLayerRecreatedWithTransformAnimation) {
  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));

  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
  gfx::Transform target_transform;
  target_transform.Skew(10.0, 5.0);
  window->SetTransform(target_transform);
  EXPECT_TRUE(window->layer()->GetAnimator()->IsAnimatingProperty(
      ui::LayerAnimationElement::TRANSFORM));

  window->AddObserver(this);

  EXPECT_EQ(0, layer_recreated_info().count);
  EXPECT_EQ(0, window_transformed_info().changed_count);
  std::unique_ptr<ui::Layer> old_layer = window->RecreateLayer();
  EXPECT_EQ(1, layer_recreated_info().count);
  EXPECT_EQ(window.get(), layer_recreated_info().window);
  EXPECT_EQ(1, window_transformed_info().changed_count);
  EXPECT_EQ(window.get(), window_transformed_info().window);
  EXPECT_EQ(ui::PropertyChangeReason::FROM_ANIMATION,
            window_transformed_info().reason);
}

TEST_F(WindowTest, AcquireLayer) {
  std::unique_ptr<Window> window1(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  std::unique_ptr<Window> window2(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 2}));
  ui::Layer* parent = window1->parent()->layer();
  EXPECT_EQ(2U, parent->children().size());

  WindowTestApi window1_test_api(window1.get());
  WindowTestApi window2_test_api(window2.get());

  EXPECT_TRUE(window1_test_api.OwnsLayer());
  EXPECT_TRUE(window2_test_api.OwnsLayer());

  // After acquisition, window1 should not own its layer, but it should still
  // be available to the window.
  std::unique_ptr<ui::Layer> window1_layer(window1->AcquireLayer());
  EXPECT_FALSE(window1_test_api.OwnsLayer());
  EXPECT_TRUE(window1_layer.get() == window1->layer());

  // The acquired layer's owner should be set NULL and re-acquring
  // should return NULL.
  EXPECT_FALSE(window1_layer->owner());
  std::unique_ptr<ui::Layer> window1_layer_reacquired(window1->AcquireLayer());
  EXPECT_FALSE(window1_layer_reacquired.get());

  // Upon destruction, window1's layer should still be valid, and in the layer
  // hierarchy, but window2's should be gone, and no longer in the hierarchy.
  window1.reset();
  window2.reset();

  // This should be set by the window's destructor.
  EXPECT_FALSE(window1_layer->delegate());
  EXPECT_EQ(1U, parent->children().size());
}

// Make sure that properties which should persist from the old layer to the new
// layer actually do.
TEST_F(WindowTest, RecreateLayer) {
  // Set properties to non default values.
  gfx::Rect window_bounds(100, 100);
  Window w(new ColorTestWindowDelegate(SK_ColorWHITE));
  w.SetId(1);
  w.Init(ui::LAYER_SOLID_COLOR);
  w.SetBounds(window_bounds);

  ui::Layer* layer = w.layer();
  layer->SetVisible(false);
  layer->SetMasksToBounds(true);

  ui::Layer child_layer;
  layer->Add(&child_layer);

  std::unique_ptr<ui::Layer> old_layer(w.RecreateLayer());
  layer = w.layer();
  EXPECT_EQ(ui::LAYER_SOLID_COLOR, layer->type());
  EXPECT_FALSE(layer->visible());
  EXPECT_EQ(1u, layer->children().size());
  EXPECT_TRUE(layer->GetMasksToBounds());
  EXPECT_EQ("0,0 100x100", w.bounds().ToString());
  EXPECT_EQ("0,0 100x100", layer->bounds().ToString());
}

// Verify that RecreateLayer() stacks the old layer above the newly creatd
// layer.
TEST_F(WindowTest, RecreateLayerZOrder) {
  std::unique_ptr<Window> w = CreateTestWindow(
      {.parent = root_window(), .bounds = {0, 0, 100, 100}, .window_id = 1},
      SK_ColorWHITE);
  std::unique_ptr<ui::Layer> old_layer(w->RecreateLayer());

  const std::vector<raw_ptr<ui::Layer, VectorExperimental>>& child_layers =
      root_window()->layer()->children();
  ASSERT_EQ(2u, child_layers.size());
  EXPECT_EQ(w->layer(), child_layers[0]);
  EXPECT_EQ(old_layer.get(), child_layers[1]);
}

// Ensure that acquiring a layer then recreating a layer does not crash
// and that RecreateLayer returns null.
TEST_F(WindowTest, AcquireThenRecreateLayer) {
  std::unique_ptr<Window> w = CreateTestWindow(
      {.parent = root_window(), .bounds = {0, 0, 100, 100}, .window_id = 1},
      SK_ColorWHITE);
  std::unique_ptr<ui::Layer> acquired_layer(w->AcquireLayer());
  std::unique_ptr<ui::Layer> doubly_acquired_layer(w->RecreateLayer());
  EXPECT_FALSE(doubly_acquired_layer);

  // Destroy window before layer gets destroyed.
  w.reset();
}

class TestVisibilityClient : public client::VisibilityClient {
 public:
  explicit TestVisibilityClient(Window* root_window)
      : ignore_visibility_changes_(false) {
    client::SetVisibilityClient(root_window, this);
  }

  TestVisibilityClient(const TestVisibilityClient&) = delete;
  TestVisibilityClient& operator=(const TestVisibilityClient&) = delete;

  ~TestVisibilityClient() override {}

  void set_ignore_visibility_changes(bool ignore_visibility_changes) {
    ignore_visibility_changes_ = ignore_visibility_changes;
  }

  // Overridden from client::VisibilityClient:
  void UpdateLayerVisibility(aura::Window* window, bool visible) override {
    if (!ignore_visibility_changes_)
      window->layer()->SetVisible(visible);
  }

 private:
  bool ignore_visibility_changes_;
};

TEST_F(WindowTest, VisibilityClientIsVisible) {
  TestVisibilityClient client(root_window());

  std::unique_ptr<Window> window(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  EXPECT_TRUE(window->IsVisible());
  EXPECT_TRUE(window->layer()->visible());

  window->Hide();
  EXPECT_FALSE(window->IsVisible());
  EXPECT_FALSE(window->layer()->visible());
  window->Show();

  client.set_ignore_visibility_changes(true);
  window->Hide();
  EXPECT_FALSE(window->IsVisible());
  EXPECT_TRUE(window->layer()->visible());
}

// Tests the mouse events seen by WindowDelegates in a Window hierarchy when
// changing the properties of a leaf Window.
TEST_F(WindowTest, MouseEventsOnLeafWindowChange) {
  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseTo(50, 50);

  EventCountDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {100, 100},
                                    .window_id = 1}));
  RunAllPendingInMessageLoop();
  // The format of result is "Enter/Move/Leave".
  EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());

  // Add new window |w11| on top of |w1| which contains the cursor.
  EventCountDelegate d11;
  std::unique_ptr<Window> w11(
      aura::test::CreateTestWindow({.delegate = &d11,
                                    .parent = w1.get(),
                                    .bounds = {100, 100},
                                    .window_id = 1}));
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());

  // Resize |w11| so that it does not contain the cursor.
  w11->SetBounds(gfx::Rect(0, 0, 10, 10));
  RunAllPendingInMessageLoop();
  EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 1", d11.GetMouseMotionCountsAndReset());

  // Resize |w11| so that it does contain the cursor.
  w11->SetBounds(gfx::Rect(0, 0, 60, 60));
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());

  // Detach |w11| from |w1|.
  w1->RemoveChild(w11.get());
  RunAllPendingInMessageLoop();
  EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 1", d11.GetMouseMotionCountsAndReset());

  // Re-attach |w11| to |w1|.
  w1->AddChild(w11.get());
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());

  // Hide |w11|.
  w11->Hide();
  RunAllPendingInMessageLoop();
  EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 1", d11.GetMouseMotionCountsAndReset());

  // Show |w11|.
  w11->Show();
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());

  // Translate |w11| so that it does not contain the mouse cursor.
  gfx::Transform transform;
  transform.Translate(100, 100);
  w11->SetTransform(transform);
  RunAllPendingInMessageLoop();
  EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 1", d11.GetMouseMotionCountsAndReset());

  // Clear the transform on |w11| so that it does contain the cursor.
  w11->SetTransform(gfx::Transform());
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("1 1 0", d11.GetMouseMotionCountsAndReset());

  // Close |w11|. Note that since |w11| is being destroyed, its delegate should
  // not see any further events.
  w11.reset();
  RunAllPendingInMessageLoop();
  EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());

  // Move the mouse outside the bounds of the root window. Since the mouse
  // cursor is no longer within their bounds, the delegates of the child
  // windows should not see any mouse events.
  generator.MoveMouseTo(-10, -10);
  EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());

  // Add |w11|.
  w11 = aura::test::CreateTestWindow({.delegate = &d11,
                                      .parent = w1.get(),
                                      .bounds = {100, 100},
                                      .window_id = 1});
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());

  // Close |w11|.
  w11.reset();
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());
}

// Tests the mouse events seen by WindowDelegates in a Window hierarchy when
// deleting a non-leaf Window.
TEST_F(WindowTest, MouseEventsOnNonLeafWindowDelete) {
  ui::test::EventGenerator generator(root_window());
  generator.MoveMouseTo(50, 50);

  EventCountDelegate d1;
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = &d1,
                                    .parent = root_window(),
                                    .bounds = {100, 100},
                                    .window_id = 1}));
  RunAllPendingInMessageLoop();
  // The format of result is "Enter/Move/Leave".
  EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());

  // Add new window |w2| on top of |w1| which contains the cursor.
  EventCountDelegate d2;
  std::unique_ptr<Window> w2(aura::test::CreateTestWindow({.delegate = &d2,
                                                           .parent = w1.get(),
                                                           .bounds = {100, 100},
                                                           .window_id = 1}));
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 1", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("1 1 0", d2.GetMouseMotionCountsAndReset());

  // Add new window on top of |w2| which contains the cursor.
  EventCountDelegate d3;
  aura::test::CreateTestWindow({.delegate = &d3,
                                .parent = w2.get(),
                                .bounds = {100, 100},
                                .window_id = 1})
      .release();
  RunAllPendingInMessageLoop();
  EXPECT_EQ("0 0 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 1", d2.GetMouseMotionCountsAndReset());
  EXPECT_EQ("1 1 0", d3.GetMouseMotionCountsAndReset());

  // Delete |w2|, which will also delete its owned child window. Since |w2| and
  // its child are in the process of being destroyed, their delegates should
  // not see any further events.
  w2.reset();
  RunAllPendingInMessageLoop();
  EXPECT_EQ("1 1 0", d1.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 0", d2.GetMouseMotionCountsAndReset());
  EXPECT_EQ("0 0 0", d3.GetMouseMotionCountsAndReset());
}

class RootWindowAttachmentObserver : public WindowObserver {
 public:
  RootWindowAttachmentObserver() : added_count_(0), removed_count_(0) {}

  RootWindowAttachmentObserver(const RootWindowAttachmentObserver&) = delete;
  RootWindowAttachmentObserver& operator=(const RootWindowAttachmentObserver&) =
      delete;

  ~RootWindowAttachmentObserver() override {}

  int added_count() const { return added_count_; }
  int removed_count() const { return removed_count_; }

  void Clear() {
    added_count_ = 0;
    removed_count_ = 0;
  }

  // Overridden from WindowObserver:
  void OnWindowAddedToRootWindow(Window* window) override { ++added_count_; }
  void OnWindowRemovingFromRootWindow(Window* window,
                                      Window* new_root) override {
    ++removed_count_;
  }

 private:
  int added_count_;
  int removed_count_;
};

TEST_F(WindowTest, RootWindowAttachment) {
  RootWindowAttachmentObserver observer;

  // Test a direct add/remove from the RootWindow.
  std::unique_ptr<Window> w1(new Window(nullptr));
  w1->Init(ui::LAYER_NOT_DRAWN);
  w1->AddObserver(&observer);

  ParentWindow(w1.get());
  EXPECT_EQ(1, observer.added_count());
  EXPECT_EQ(0, observer.removed_count());

  w1.reset();
  EXPECT_EQ(1, observer.added_count());
  EXPECT_EQ(1, observer.removed_count());

  observer.Clear();

  // Test an indirect add/remove from the RootWindow.
  w1 = std::make_unique<Window>(nullptr);
  w1->Init(ui::LAYER_NOT_DRAWN);
  Window* w11 = new Window(nullptr);
  w11->Init(ui::LAYER_NOT_DRAWN);
  w11->AddObserver(&observer);
  w1->AddChild(w11);
  EXPECT_EQ(0, observer.added_count());
  EXPECT_EQ(0, observer.removed_count());

  ParentWindow(w1.get());
  EXPECT_EQ(1, observer.added_count());
  EXPECT_EQ(0, observer.removed_count());

  w1.reset();  // Deletes w11.
  w11 = nullptr;
  EXPECT_EQ(1, observer.added_count());
  EXPECT_EQ(1, observer.removed_count());

  observer.Clear();

  // Test an indirect add/remove with nested observers.
  w1 = std::make_unique<Window>(nullptr);
  w1->Init(ui::LAYER_NOT_DRAWN);
  w11 = new Window(nullptr);
  w11->Init(ui::LAYER_NOT_DRAWN);
  w11->AddObserver(&observer);
  w1->AddChild(w11);
  Window* w111 = new Window(nullptr);
  w111->Init(ui::LAYER_NOT_DRAWN);
  w111->AddObserver(&observer);
  w11->AddChild(w111);

  EXPECT_EQ(0, observer.added_count());
  EXPECT_EQ(0, observer.removed_count());

  ParentWindow(w1.get());
  EXPECT_EQ(2, observer.added_count());
  EXPECT_EQ(0, observer.removed_count());

  w1.reset();  // Deletes w11 and w111.
  w11 = nullptr;
  w111 = nullptr;
  EXPECT_EQ(2, observer.added_count());
  EXPECT_EQ(2, observer.removed_count());
}

class BoundsChangedWindowObserver : public WindowObserver {
 public:
  BoundsChangedWindowObserver() : root_set_(false) {}

  BoundsChangedWindowObserver(const BoundsChangedWindowObserver&) = delete;
  BoundsChangedWindowObserver& operator=(const BoundsChangedWindowObserver&) =
      delete;

  void OnWindowBoundsChanged(Window* window,
                             const gfx::Rect& old_bounds,
                             const gfx::Rect& new_bounds,
                             ui::PropertyChangeReason reason) override {
    root_set_ = !!window->GetRootWindow();
  }

  bool root_set() const { return root_set_; }

 private:
  bool root_set_;
};

TEST_F(WindowTest, RootWindowSetWhenReparenting) {
  Window parent1(nullptr);
  parent1.Init(ui::LAYER_NOT_DRAWN);
  Window parent2(nullptr);
  parent2.Init(ui::LAYER_NOT_DRAWN);
  ParentWindow(&parent1);
  ParentWindow(&parent2);
  parent1.SetBounds(gfx::Rect(10, 10, 300, 300));
  parent2.SetBounds(gfx::Rect(20, 20, 300, 300));

  BoundsChangedWindowObserver observer;
  Window child(nullptr);
  child.Init(ui::LAYER_NOT_DRAWN);
  child.SetBounds(gfx::Rect(5, 5, 100, 100));
  parent1.AddChild(&child);

  // We need animations to start in order to observe the bounds changes.
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  ui::ScopedLayerAnimationSettings settings1(child.layer()->GetAnimator());
  settings1.SetTransitionDuration(base::Milliseconds(100));
  gfx::Rect new_bounds(gfx::Rect(35, 35, 50, 50));
  child.SetBounds(new_bounds);

  child.AddObserver(&observer);

  // Reparenting the |child| will cause it to get moved. During this move
  // the window should still have root window set.
  parent2.AddChild(&child);
  EXPECT_TRUE(observer.root_set());

  // Animations should stop and the bounds should be as set before the |child|
  // got reparented.
  EXPECT_EQ(new_bounds.ToString(), child.GetTargetBounds().ToString());
  EXPECT_EQ(new_bounds.ToString(), child.bounds().ToString());
  EXPECT_EQ("55,55 50x50", child.GetBoundsInRootWindow().ToString());
}

TEST_F(WindowTest, OwnedByParentFalse) {
  // By default, a window is owned by its parent. If this is set to false, the
  // window will not be destroyed when its parent is.

  std::unique_ptr<Window> w1(new Window(nullptr));
  w1->Init(ui::LAYER_NOT_DRAWN);
  std::unique_ptr<Window> w2(new Window(nullptr));
  w2->set_owned_by_parent(false);
  w2->Init(ui::LAYER_NOT_DRAWN);
  w1->AddChild(w2.get());

  w1.reset();

  // We should be able to deref w2 still, but its parent should now be NULL.
  EXPECT_FALSE(w2->parent());
}

// Used By DeleteWindowFromOnWindowDestroyed. Destroys a Window from
// OnWindowDestroyed().
class OwningWindowDelegate : public TestWindowDelegate {
 public:
  OwningWindowDelegate() {}

  OwningWindowDelegate(const OwningWindowDelegate&) = delete;
  OwningWindowDelegate& operator=(const OwningWindowDelegate&) = delete;

  void SetOwnedWindow(Window* window) {
    owned_window_.reset(window);
  }

  void OnWindowDestroyed(Window* window) override { owned_window_.reset(); }

 private:
  std::unique_ptr<Window> owned_window_;
};

// Creates a window with two child windows. When the first child window is
// destroyed (WindowDelegate::OnWindowDestroyed) it deletes the second child.
// This synthesizes BrowserView and the status bubble. Both are children of the
// same parent and destroying BrowserView triggers it destroying the status
// bubble.
TEST_F(WindowTest, DeleteWindowFromOnWindowDestroyed) {
  std::unique_ptr<Window> parent(new Window(nullptr));
  parent->Init(ui::LAYER_NOT_DRAWN);
  OwningWindowDelegate delegate;
  Window* c1 = new Window(&delegate);
  c1->Init(ui::LAYER_NOT_DRAWN);
  parent->AddChild(c1);
  Window* c2 = new Window(nullptr);
  c2->Init(ui::LAYER_NOT_DRAWN);
  parent->AddChild(c2);
  delegate.SetOwnedWindow(c2);
  parent.reset();
}

// WindowObserver implementation that deletes a window in
// OnWindowVisibilityChanged().
class DeleteOnVisibilityChangedObserver : public WindowObserver {
 public:
  // |to_observe| is the Window this is added as an observer to. When
  // OnWindowVisibilityChanged() is called |to_delete| is deleted.
  explicit DeleteOnVisibilityChangedObserver(Window* to_observe,
                                             Window* to_delete)
      : to_observe_(to_observe), to_delete_(to_delete) {
    to_observe_->AddObserver(this);
  }

  DeleteOnVisibilityChangedObserver(const DeleteOnVisibilityChangedObserver&) =
      delete;
  DeleteOnVisibilityChangedObserver& operator=(
      const DeleteOnVisibilityChangedObserver&) = delete;

  ~DeleteOnVisibilityChangedObserver() override {
    // OnWindowVisibilityChanged() should have been called.
    DCHECK(!to_delete_);
  }

  // WindowObserver:
  void OnWindowVisibilityChanged(Window* window, bool visible) override {
    to_observe_->RemoveObserver(this);
    to_observe_ = nullptr;
    Window* to_delete = to_delete_;
    to_delete_ = nullptr;
    delete to_delete;
  }

 private:
  raw_ptr<Window> to_observe_;
  raw_ptr<Window> to_delete_;
};

TEST_F(WindowTest, DeleteParentWindowFromOnWindowVisibiltyChanged) {
  WindowTracker tracker;
  Window* root =
      CreateTestWindow({.bounds = {100, 100}, .window_id = 0}).release();
  tracker.Add(root);
  Window* child1 =
      CreateTestWindow({.parent = root, .bounds = {100, 100}, .window_id = 0})
          .release();
  tracker.Add(child1);
  tracker.Add(
      CreateTestWindow({.parent = root, .bounds = {100, 100}, .window_id = 0})
          .release());

  // This deletes |root| (the parent) when OnWindowVisibilityChanged() is
  // received by |child1|.
  DeleteOnVisibilityChangedObserver deletion_observer(child1, root);
  // The Hide() calls trigger deleting |root|, which should delete the whole
  // tree.
  root->Hide();
  EXPECT_TRUE(tracker.windows().empty());
}

// Used by DelegateNotifiedAsBoundsChange to verify OnBoundsChanged() is
// invoked.
class BoundsChangeDelegate : public TestWindowDelegate {
 public:
  BoundsChangeDelegate() : bounds_changed_(false) {}

  BoundsChangeDelegate(const BoundsChangeDelegate&) = delete;
  BoundsChangeDelegate& operator=(const BoundsChangeDelegate&) = delete;

  void clear_bounds_changed() { bounds_changed_ = false; }
  bool bounds_changed() const {
    return bounds_changed_;
  }

  // Window
  void OnBoundsChanged(const gfx::Rect& old_bounds,
                       const gfx::Rect& new_bounds) override {
    bounds_changed_ = true;
  }

 private:
  // Was OnBoundsChanged() invoked?
  bool bounds_changed_;
};

// Verifies the delegate is notified when the actual bounds of the layer
// change.
TEST_F(WindowTest, DelegateNotifiedAsBoundsChange) {
  BoundsChangeDelegate delegate;

  // We cannot short-circuit animations in this test.
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);

  std::unique_ptr<Window> window(
      aura::test::CreateTestWindow({.delegate = &delegate,
                                    .parent = root_window(),
                                    .bounds = {100, 100},
                                    .window_id = 1}));
  window->layer()->GetAnimator()->set_disable_timer_for_test(true);

  delegate.clear_bounds_changed();

  // Animate to a different position.
  {
    ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
    window->SetBounds(gfx::Rect(100, 100, 100, 100));
  }

  // Bounds shouldn't immediately have changed.
  EXPECT_EQ("0,0 100x100", window->bounds().ToString());
  EXPECT_FALSE(delegate.bounds_changed());

  // Animate to the end, which should notify of the change.
  base::TimeTicks start_time =
      window->layer()->GetAnimator()->last_step_time();
  ui::LayerAnimator* animator = window->layer()->GetAnimator();
  animator->Step(start_time + base::Milliseconds(1000));
  EXPECT_TRUE(delegate.bounds_changed());
  EXPECT_NE("0,0 100x100", window->bounds().ToString());
}

// Verifies the delegate is notified when the actual bounds of the layer
// change even when the window is not the layer's delegate
TEST_F(WindowTest, DelegateNotifiedAsBoundsChangeInHiddenLayer) {
  BoundsChangeDelegate delegate;

  // We cannot short-circuit animations in this test.
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);

  std::unique_ptr<Window> window(
      aura::test::CreateTestWindow({.delegate = &delegate,
                                    .parent = root_window(),
                                    .bounds = {100, 100},
                                    .window_id = 1}));
  window->layer()->GetAnimator()->set_disable_timer_for_test(true);

  delegate.clear_bounds_changed();

  // Suppress paint on the layer since it is hidden (should reset the layer's
  // delegate to NULL)
  window->layer()->SuppressPaint();
  EXPECT_FALSE(window->layer()->delegate());

  // Animate to a different position.
  {
    ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
    window->SetBounds(gfx::Rect(100, 100, 110, 100));
  }

  // Layer delegate is NULL but we should still get bounds changed notification.
  EXPECT_EQ("100,100 110x100", window->GetTargetBounds().ToString());
  EXPECT_TRUE(delegate.bounds_changed());

  delegate.clear_bounds_changed();

  // Animate to the end: will *not* notify of the change since we are hidden.
  base::TimeTicks start_time =
      window->layer()->GetAnimator()->last_step_time();
  ui::LayerAnimator* animator = window->layer()->GetAnimator();
  animator->Step(start_time + base::Milliseconds(1000));

  // No bounds changed notification at the end of animation since layer
  // delegate is NULL.
  EXPECT_FALSE(delegate.bounds_changed());
  EXPECT_NE("0,0 100x100", window->layer()->bounds().ToString());
}

// Used by AddChildNotifications to track notification counts.
class AddChildNotificationsObserver : public WindowObserver {
 public:
  AddChildNotificationsObserver() : added_count_(0), removed_count_(0) {}

  AddChildNotificationsObserver(const AddChildNotificationsObserver&) = delete;
  AddChildNotificationsObserver& operator=(
      const AddChildNotificationsObserver&) = delete;

  std::string CountStringAndReset() {
    std::string result = base::NumberToString(added_count_) + " " +
                         base::NumberToString(removed_count_);
    added_count_ = removed_count_ = 0;
    return result;
  }

  // WindowObserver overrides:
  void OnWindowAddedToRootWindow(Window* window) override { added_count_++; }
  void OnWindowRemovingFromRootWindow(Window* window,
                                      Window* new_root) override {
    removed_count_++;
  }

 private:
  int added_count_;
  int removed_count_;
};

// Assertions around when root window notifications are sent.
TEST_F(WindowTest, AddChildNotifications) {
  AddChildNotificationsObserver observer;
  std::unique_ptr<Window> w1(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  std::unique_ptr<Window> w2(CreateTestWindow(
      {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
  w2->AddObserver(&observer);
  w2->Focus();
  EXPECT_TRUE(w2->HasFocus());

  // Move |w2| to be a child of |w1|.
  w1->AddChild(w2.get());
  // Sine we moved in the same root, observer shouldn't be notified.
  EXPECT_EQ("0 0", observer.CountStringAndReset());
  // |w2| should still have focus after moving.
  EXPECT_TRUE(w2->HasFocus());
}

// Tests that a delegate that destroys itself when the window is destroyed does
// not break.
TEST_F(WindowTest, DelegateDestroysSelfOnWindowDestroy) {
  std::unique_ptr<Window> w1(
      aura::test::CreateTestWindow({.delegate = new DestroyWindowDelegate(),
                                    .parent = root_window(),
                                    .bounds = {10, 20, 30, 40}}));
}

class HierarchyObserver : public WindowObserver {
 public:
  explicit HierarchyObserver(Window* target) : target_(target) {
    target_->AddObserver(this);
  }

  HierarchyObserver(const HierarchyObserver&) = delete;
  HierarchyObserver& operator=(const HierarchyObserver&) = delete;

  ~HierarchyObserver() override { target_->RemoveObserver(this); }

  void ValidateState(
      int index,
      const WindowObserver::HierarchyChangeParams& params) const {
    ParamsMatch(params_[index], params);
  }

  void Reset() {
    params_.clear();
  }

 private:
  // Overridden from WindowObserver:
  void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override {
    params_.push_back(params);
  }
  void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override {
    params_.push_back(params);
  }

  void ParamsMatch(const WindowObserver::HierarchyChangeParams& p1,
                   const WindowObserver::HierarchyChangeParams& p2) const {
    EXPECT_EQ(p1.phase, p2.phase);
    EXPECT_EQ(p1.target, p2.target);
    EXPECT_EQ(p1.new_parent, p2.new_parent);
    EXPECT_EQ(p1.old_parent, p2.old_parent);
    EXPECT_EQ(p1.receiver, p2.receiver);
  }

  raw_ptr<Window> target_;
  std::vector<WindowObserver::HierarchyChangeParams> params_;
};

// Tests hierarchy change notifications.
TEST_F(WindowTest, OnWindowHierarchyChange) {
  {
    // Simple add & remove.
    HierarchyObserver oroot(root_window());

    std::unique_ptr<Window> w1(
        CreateTestWindow({.bounds = {100, 100}, .window_id = 1}));
    HierarchyObserver o1(w1.get());

    // Add.
    root_window()->AddChild(w1.get());

    WindowObserver::HierarchyChangeParams params;
    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
    params.target = w1.get();
    params.old_parent = nullptr;
    params.new_parent = root_window();
    params.receiver = w1.get();
    o1.ValidateState(0, params);

    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
    params.receiver = w1.get();
    o1.ValidateState(1, params);

    params.receiver = root_window();
    oroot.ValidateState(0, params);

    // Remove.
    o1.Reset();
    oroot.Reset();

    root_window()->RemoveChild(w1.get());

    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
    params.old_parent = root_window();
    params.new_parent = nullptr;
    params.receiver = w1.get();

    o1.ValidateState(0, params);

    params.receiver = root_window();
    oroot.ValidateState(0, params);

    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
    params.receiver = w1.get();
    o1.ValidateState(1, params);
  }

  {
    // Add & remove of hierarchy. Tests notification order per documentation in
    // WindowObserver.
    HierarchyObserver o(root_window());
    std::unique_ptr<Window> w1(
        CreateTestWindow({.bounds = {100, 100}, .window_id = 1}));
    Window* w11 =
        CreateTestWindow(
            {.parent = w1.get(), .bounds = {100, 100}, .window_id = 11})
            .release();
    w1->AddObserver(&o);
    w11->AddObserver(&o);

    // Add.
    root_window()->AddChild(w1.get());

    // Dispatched to target first.
    int index = 0;
    WindowObserver::HierarchyChangeParams params;
    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
    params.target = w1.get();
    params.old_parent = nullptr;
    params.new_parent = root_window();
    params.receiver = w1.get();
    o.ValidateState(index++, params);

    // Dispatched to target's children.
    params.receiver = w11;
    o.ValidateState(index++, params);

    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;

    // Now process the "changed" phase.
    params.receiver = w1.get();
    o.ValidateState(index++, params);
    params.receiver = w11;
    o.ValidateState(index++, params);
    params.receiver = root_window();
    o.ValidateState(index++, params);

    // Remove.
    root_window()->RemoveChild(w1.get());
    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
    params.old_parent = root_window();
    params.new_parent = nullptr;
    params.receiver = w1.get();
    o.ValidateState(index++, params);
    params.receiver = w11;
    o.ValidateState(index++, params);
    params.receiver = root_window();
    o.ValidateState(index++, params);
    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
    params.receiver = w1.get();
    o.ValidateState(index++, params);
    params.receiver = w11;
    o.ValidateState(index++, params);

    w1.reset();
  }

  {
    // Reparent. Tests notification order per documentation in WindowObserver.
    std::unique_ptr<Window> w1(CreateTestWindow(
        {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
    Window* w11 =
        CreateTestWindow(
            {.parent = w1.get(), .bounds = {100, 100}, .window_id = 11})
            .release();
    Window* w111 = CreateTestWindow(
                       {.parent = w11, .bounds = {100, 100}, .window_id = 111})
                       .release();
    std::unique_ptr<Window> w2(CreateTestWindow(
        {.parent = root_window(), .bounds = {100, 100}, .window_id = 2}));

    HierarchyObserver o(root_window());
    w1->AddObserver(&o);
    w11->AddObserver(&o);
    w111->AddObserver(&o);
    w2->AddObserver(&o);

    w2->AddChild(w11);

    // Dispatched to target first.
    int index = 0;
    WindowObserver::HierarchyChangeParams params;
    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
    params.target = w11;
    params.old_parent = w1.get();
    params.new_parent = w2.get();
    params.receiver = w11;
    o.ValidateState(index++, params);

    // Then to target's children.
    params.receiver = w111;
    o.ValidateState(index++, params);

    // Then to target's old parent chain.
    params.receiver = w1.get();
    o.ValidateState(index++, params);
    params.receiver = root_window();
    o.ValidateState(index++, params);

    // "Changed" phase.
    params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
    params.receiver = w11;
    o.ValidateState(index++, params);
    params.receiver = w111;
    o.ValidateState(index++, params);
    params.receiver = w2.get();
    o.ValidateState(index++, params);
    params.receiver = root_window();
    o.ValidateState(index++, params);

    w1.reset();
    w2.reset();
  }
}

class TestLayerAnimationObserver : public ui::LayerAnimationObserver {
 public:
  TestLayerAnimationObserver()
      : animation_completed_(false),
        animation_aborted_(false) {}

  TestLayerAnimationObserver(const TestLayerAnimationObserver&) = delete;
  TestLayerAnimationObserver& operator=(const TestLayerAnimationObserver&) =
      delete;

  ~TestLayerAnimationObserver() override {}

  bool animation_completed() const { return animation_completed_; }
  bool animation_aborted() const { return animation_aborted_; }

  void Reset() {
    animation_completed_ = false;
    animation_aborted_ = false;
  }

 private:
  // ui::LayerAnimationObserver:
  void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {
    animation_completed_ = true;
  }

  void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {
    animation_aborted_ = true;
  }

  void OnLayerAnimationScheduled(
      ui::LayerAnimationSequence* sequence) override {}

  bool animation_completed_;
  bool animation_aborted_;
};

TEST_F(WindowTest, WindowDestroyCompletesAnimations) {
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  scoped_refptr<ui::LayerAnimator> animator =
      ui::LayerAnimator::CreateImplicitAnimator();
  TestLayerAnimationObserver observer;
  animator->AddObserver(&observer);
  // Make sure destroying a Window completes the animation.
  {
    std::unique_ptr<Window> window(CreateTestWindow(
        {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
    window->layer()->SetAnimator(animator.get());

    gfx::Transform transform;
    transform.Scale(0.5f, 0.5f);
    window->SetTransform(transform);

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FALSE(observer.animation_completed());
  }
  EXPECT_TRUE(animator.get());
  EXPECT_FALSE(animator->is_animating());
  EXPECT_TRUE(observer.animation_completed());
  EXPECT_FALSE(observer.animation_aborted());
  animator->RemoveObserver(&observer);
  observer.Reset();

  animator = ui::LayerAnimator::CreateImplicitAnimator();
  animator->AddObserver(&observer);
  ui::Layer layer;
  layer.SetAnimator(animator.get());
  {
    std::unique_ptr<Window> window(CreateTestWindow(
        {.parent = root_window(), .bounds = {100, 100}, .window_id = 1}));
    window->layer()->Add(&layer);

    gfx::Transform transform;
    transform.Scale(0.5f, 0.5f);
    layer.SetTransform(transform);

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FALSE(observer.animation_completed());
  }

  EXPECT_TRUE(animator.get());
  EXPECT_FALSE(animator->is_animating());
  EXPECT_TRUE(observer.animation_completed());
  EXPECT_FALSE(observer.animation_aborted());
  animator->RemoveObserver(&observer);
}

TEST_F(WindowTest, RootWindowUsesCompositorFrameSinkId) {
  EXPECT_EQ(host()->compositor()->frame_sink_id(),
            root_window()->GetFrameSinkId());
  EXPECT_TRUE(root_window()->GetFrameSinkId().is_valid());
}

TEST_F(WindowTest, LocalSurfaceIdChanges) {
  Window window(nullptr);
  window.Init(ui::LAYER_NOT_DRAWN);
  window.SetBounds(gfx::Rect(300, 300));

  root_window()->AddChild(&window);

  std::unique_ptr<cc::LayerTreeFrameSink> frame_sink(
      window.CreateLayerTreeFrameSink());
  viz::LocalSurfaceId local_surface_id1 = window.GetLocalSurfaceId();
  EXPECT_NE(nullptr, frame_sink.get());
  EXPECT_TRUE(local_surface_id1.is_valid());

  // Resize to 0x0 to make sure the correct window size is stored before
  // creating the frame sink.
  window.SetBounds(gfx::Rect(0, 0));
  viz::LocalSurfaceId local_surface_id2 = window.GetLocalSurfaceId();
  EXPECT_TRUE(local_surface_id2.is_valid());
  EXPECT_NE(local_surface_id1, local_surface_id2);

  window.SetBounds(gfx::Rect(300, 300));
  viz::LocalSurfaceId local_surface_id3 = window.GetLocalSurfaceId();
  EXPECT_TRUE(local_surface_id3.is_valid());
  EXPECT_NE(local_surface_id1, local_surface_id3);
  EXPECT_NE(local_surface_id2, local_surface_id3);

  window.OnDeviceScaleFactorChanged(1.0f, 3.0f);
  viz::LocalSurfaceId local_surface_id4 = window.GetLocalSurfaceId();
  EXPECT_TRUE(local_surface_id4.is_valid());
  EXPECT_NE(local_surface_id1, local_surface_id4);
  EXPECT_NE(local_surface_id2, local_surface_id4);
  EXPECT_NE(local_surface_id3, local_surface_id4);

  window.RecreateLayer();
  viz::LocalSurfaceId local_surface_id5 = window.GetLocalSurfaceId();
  EXPECT_TRUE(local_surface_id5.is_valid());
  EXPECT_NE(local_surface_id1, local_surface_id5);
  EXPECT_NE(local_surface_id2, local_surface_id5);
  EXPECT_NE(local_surface_id3, local_surface_id5);
  EXPECT_NE(local_surface_id4, local_surface_id5);

  window.AllocateLocalSurfaceId();
  viz::LocalSurfaceId local_surface_id6 = window.GetLocalSurfaceId();
  EXPECT_TRUE(local_surface_id6.is_valid());
  EXPECT_NE(local_surface_id1, local_surface_id6);
  EXPECT_NE(local_surface_id2, local_surface_id6);
  EXPECT_NE(local_surface_id3, local_surface_id6);
  EXPECT_NE(local_surface_id4, local_surface_id6);
  EXPECT_NE(local_surface_id5, local_surface_id6);
}

TEST_F(WindowTest, CreateLayerTreeFrameSink) {
  Window window(nullptr);
  window.Init(ui::LAYER_NOT_DRAWN);
  window.SetBounds(gfx::Rect(300, 300));

  root_window()->AddChild(&window);

  // The window shouldn't have FrameSinkId before CreateLayerTreeFrameSink() is
  // called.
  EXPECT_FALSE(window.GetFrameSinkId().is_valid());

  std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink =
      window.CreateLayerTreeFrameSink();

  // Calling CreateLayerTreeFrameSink() should return a LayerTreeFrameSink and
  // the window should now have a FrameSinkId.
  EXPECT_NE(layer_tree_frame_sink.get(), nullptr);
  EXPECT_TRUE(window.GetFrameSinkId().is_valid());

  viz::FrameSinkId frame_sink_id = window.GetFrameSinkId();

  // Reset and recreate the LayerTreeFrameSink. This would typically happen
  // after a GPU crash.
  layer_tree_frame_sink.reset();
  layer_tree_frame_sink = window.CreateLayerTreeFrameSink();

  // A new LayerTreeFrameSink should be created for the same FrameSinkId.
  EXPECT_NE(layer_tree_frame_sink.get(), nullptr);
  EXPECT_EQ(frame_sink_id, window.GetFrameSinkId());
}

// This delegate moves its parent window to the specified one when the gesture
// ends.
class HandleGestureEndDelegate : public TestWindowDelegate {
 public:
  explicit HandleGestureEndDelegate(
      base::OnceCallback<void(Window*)> on_gesture_end)
      : on_gesture_end_(std::move(on_gesture_end)) {}

  HandleGestureEndDelegate(const HandleGestureEndDelegate&) = delete;
  HandleGestureEndDelegate& operator=(const HandleGestureEndDelegate&) = delete;

  ~HandleGestureEndDelegate() override = default;

 private:
  // WindowDelegate:
  void OnGestureEvent(ui::GestureEvent* event) override {
    switch (event->type()) {
      case ui::EventType::kGestureScrollEnd:
      case ui::EventType::kGestureEnd:
      case ui::EventType::kGesturePinchEnd: {
        if (on_gesture_end_)
          std::move(on_gesture_end_).Run(static_cast<Window*>(event->target()));
        break;
      }
      default:
        break;
    }
  }

  base::OnceCallback<void(Window*)> on_gesture_end_;
};

TEST_F(WindowTest, CleanupGestureStateChangesWindowHierarchy) {
  Window window(nullptr);
  window.Init(ui::LAYER_NOT_DRAWN);
  root_window()->AddChild(&window);
  window.SetBounds(gfx::Rect(0, 0, 100, 100));
  window.Show();
  Window window2(nullptr);
  window2.Init(ui::LAYER_NOT_DRAWN);
  root_window()->AddChild(&window2);
  root_window()->StackChildAtBottom(&window2);
  window2.Show();
  HandleGestureEndDelegate delegate(base::BindLambdaForTesting(
      [&](Window* target_window) { window2.AddChild(target_window); }));
  std::unique_ptr<Window> child = std::make_unique<Window>(&delegate);
  child->Init(ui::LAYER_NOT_DRAWN);
  window.AddChild(child.get());
  child->SetBounds(gfx::Rect(0, 0, 100, 100));
  child->Show();
  EXPECT_EQ(1u, window.children().size());
  EXPECT_EQ(0u, window2.children().size());

  ui::test::EventGenerator event_generator(root_window(), child.get());
  event_generator.PressTouch();
  window.CleanupGestureState();
  EXPECT_EQ(0u, window.children().size());
  EXPECT_EQ(1u, window2.children().size());
  child.reset();
}

TEST_F(WindowTest, CleanupGestureStateDeleteOtherWindows) {
  Window window(nullptr);
  window.Init(ui::LAYER_NOT_DRAWN);
  root_window()->AddChild(&window);
  window.SetBounds(gfx::Rect(0, 0, 200, 200));
  window.Show();
  std::unique_ptr<Window> child1 = std::make_unique<Window>(nullptr);
  child1->Init(ui::LAYER_NOT_DRAWN);
  child1->SetBounds(gfx::Rect(100, 100, 100, 100));
  window.AddChild(child1.get());
  child1->Show();
  HandleGestureEndDelegate delegate(base::BindLambdaForTesting(
      [&](Window* target_window) { child1.reset(); }));
  std::unique_ptr<Window> child2 = std::make_unique<Window>(&delegate);
  child2->Init(ui::LAYER_NOT_DRAWN);
  window.AddChild(child2.get());
  child2->SetBounds(gfx::Rect(0, 0, 100, 100));
  child2->Show();
  window.StackChildAtBottom(child2.get());
  EXPECT_EQ(2u, window.children().size());
  EXPECT_EQ(child2.get(), window.children().front());

  ui::test::EventGenerator event_generator(root_window(), child2.get());
  event_generator.PressTouch();
  window.CleanupGestureState();
  EXPECT_EQ(1u, window.children().size());
  EXPECT_FALSE(child1);
  child2.reset();
}

class TestTouchWindowDelegate : public TestWindowDelegate {
 public:
  explicit TestTouchWindowDelegate() = default;
  TestTouchWindowDelegate(const TestTouchWindowDelegate&) = delete;
  TestTouchWindowDelegate& operator=(const TestTouchWindowDelegate&) = delete;
  ~TestTouchWindowDelegate() override = default;

  void OnTouchEvent(ui::TouchEvent* event) override {
    if (event->type() == ui::EventType::kTouchCancelled) {
      if (on_touch_cancel_callback_) {
        std::move(on_touch_cancel_callback_)
            .Run(static_cast<Window*>(event->target()));
      }
    }
  }

  void SetOnTouchCancelCallback(base::OnceCallback<void(Window*)> callback) {
    on_touch_cancel_callback_ = std::move(callback);
  }

 private:
  base::OnceCallback<void(Window*)> on_touch_cancel_callback_;
};

// Test for use-after-free in crbug.com/1297643.
TEST_F(WindowTest, DeleteWindowWhenCancellingTouch) {
  TestTouchWindowDelegate window_delegate;
  auto window = std::make_unique<Window>(&window_delegate);
  window->Init(ui::LAYER_NOT_DRAWN);
  root_window()->AddChild(window.get());
  window->SetBounds(gfx::Rect(0, 0, 200, 200));
  window->Show();

  window_delegate.SetOnTouchCancelCallback(
      base::BindLambdaForTesting([&window](Window* target) {
        if (target == window.get()) {
          window.reset();
        }
      }));

  ui::test::EventGenerator event_generator(root_window(), window.get());
  event_generator.PressTouch();
  event_generator.MoveTouchBy(10, 10);

  auto* gesture_recognizer = Env::GetInstance()->gesture_recognizer();
  EXPECT_TRUE(gesture_recognizer->DoesConsumerHaveActiveTouch(window.get()));

  // Hide window which should cancel touch.
  window->Hide();
  // Window should've been deleted.
  EXPECT_FALSE(window);

  // Create two new windows to transfer between.
  Window window1(nullptr);
  window1.Init(ui::LAYER_NOT_DRAWN);
  root_window()->AddChild(&window1);

  Window window2(nullptr);
  window2.Init(ui::LAYER_NOT_DRAWN);
  root_window()->AddChild(&window2);

  // This should not cause use-after-free.
  gesture_recognizer->TransferEventsTo(
      &window1, &window2, ui::TransferTouchesBehavior::kDontCancel);
}

class WindowActualScreenBoundsTest
    : public WindowTest,
      public testing::WithParamInterface<
          /*is_target_transform_identical*/ bool> {
 public:
  WindowActualScreenBoundsTest() = default;
  WindowActualScreenBoundsTest(const WindowActualScreenBoundsTest&) = delete;
  WindowActualScreenBoundsTest& operator=(const WindowActualScreenBoundsTest&) =
      delete;
  ~WindowActualScreenBoundsTest() override = default;

  // WindowTest:
  void SetUp() override {
    WindowTest::SetUp();
    viewport_ = std::unique_ptr<Window>(CreateTestWindow(
        {.parent = root_window(), .bounds = {100, 50, 200, 200}}));
    child_ = std::unique_ptr<Window>(
        CreateTestWindow({.parent = viewport_.get(), .bounds = {100, 100}}));
  }

  void TearDown() override {
    child_.reset();
    viewport_.reset();
    WindowTest::TearDown();
  }

  void OnTranslationAnimationStarted(const gfx::Transform& transform) const {
    EXPECT_EQ("100,50 100x100", child_->GetActualBoundsInScreen().ToString());
    EXPECT_EQ("50,0 100x100", child_->GetBoundsInScreen().ToString());
  }

  void OnTranslationAnimationEnded(const gfx::Transform& transform) const {
    EXPECT_EQ("50,0 100x100", child_->GetActualBoundsInScreen().ToString());
    EXPECT_EQ("50,0 100x100", child_->GetBoundsInScreen().ToString());
  }

  void OnTranslationAnimationProgressed(const gfx::Rect& child_initial_bounds,
                                        const gfx::Transform& transform) const {
    EXPECT_EQ(transform.MapRect(child_initial_bounds),
              child_->GetActualBoundsInScreen());
  }

  std::unique_ptr<Window> viewport_;
  std::unique_ptr<Window> child_;
};

INSTANTIATE_TEST_SUITE_P(All, WindowActualScreenBoundsTest, testing::Bool());

// Verifies that the function to get the window's screen bounds works as
// expected during layer animation.
TEST_P(WindowActualScreenBoundsTest, VerifyWindowActualBoundsDuringAnimation) {
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);

  auto* viewport_layer = viewport_->layer();
  gfx::Transform initial_transform;
  gfx::Transform target_transform;
  gfx::Rect child_initial_bounds;
  if (GetParam()) {
    // Test in the scenario where the target transform is identical.

    // Set the target bounds.
    viewport_->SetBounds(
        gfx::Rect(/*x=*/50, /*y=*/0, /*width=*/200, /*height=*/200));

    // Set the transform to reverse the effect brought by bounds setting.
    initial_transform.Translate(50, 50);
    viewport_->layer()->SetTransform(initial_transform);

    // Trigger the translation animation.
    ui::ScopedLayerAnimationSettings settings(viewport_layer->GetAnimator());
    viewport_layer->SetTransform(target_transform);

    // Calculate the child's initial screen bounds manually.
    child_initial_bounds =
        gfx::Rect(/*x=*/50, /*y=*/0, /*width=*/100, /*height=*/100);
  } else {
    // Test in the scenario where the target transform is non-identical.

    // Trigger the translation animation.
    ui::ScopedLayerAnimationSettings settings(viewport_layer->GetAnimator());
    target_transform.Translate(-50, -50);
    viewport_layer->SetTransform(target_transform);

    // Calculate the child's initial screen bounds manually.
    child_initial_bounds =
        gfx::Rect(/*x=*/100, /*y=*/50, /*width=*/100, /*height=*/100);
  }

  LayerTranslationAnimationNotifier bounds_checker(
      viewport_layer, initial_transform, target_transform,
      base::BindRepeating(
          &WindowActualScreenBoundsTest::OnTranslationAnimationStarted,
          base::Unretained(this)),
      base::BindRepeating(
          &WindowActualScreenBoundsTest::OnTranslationAnimationEnded,
          base::Unretained(this)),
      base::BindRepeating(
          &WindowActualScreenBoundsTest::OnTranslationAnimationProgressed,
          base::Unretained(this), child_initial_bounds));
  bounds_checker.WaitForAnimationCompletion();
}

}  // namespace
}  // namespace test
}  // namespace aura