910e62b5创建于 1月15日历史提交
// Copyright 2022 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/touch_selection/touch_selection_magnifier_aura.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"

namespace ui {

namespace {

class TouchSelectionMagnifierAuraTest : public testing::Test {
 public:
  TouchSelectionMagnifierAuraTest()
      : disable_animations_(ScopedAnimationDurationScaleMode::ZERO_DURATION) {}

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

  ~TouchSelectionMagnifierAuraTest() override = default;

 private:
  ScopedAnimationDurationScaleMode disable_animations_;
};

// Tests that the magnifier is horizontally centered above a vertical caret.
TEST_F(TouchSelectionMagnifierAuraTest, BoundsForVerticalCaret) {
  TouchSelectionMagnifierAura magnifier;
  Layer magnifier_parent;
  magnifier_parent.SetBounds(gfx::Rect(500, 400));

  // Show the magnifier at a vertical caret.
  constexpr gfx::Point kCaretTop(300, 200);
  constexpr gfx::Point kCaretBottom(300, 210);
  magnifier.ShowFocusBound(&magnifier_parent, kCaretTop, kCaretBottom);

  // Magnifier should be horizontally centered above the caret.
  const gfx::Rect magnifier_bounds = magnifier.GetMagnifierBoundsForTesting();
  EXPECT_EQ(magnifier_bounds.CenterPoint().x(), kCaretTop.x());
  EXPECT_LT(magnifier_bounds.bottom(), kCaretBottom.y());

  // Zoomed content bounds should be centered on the caret.
  const gfx::Rect zoomed_contents_bounds =
      magnifier.GetZoomedContentsBoundsForTesting();
  EXPECT_EQ(zoomed_contents_bounds.CenterPoint().x(), kCaretTop.x());
  EXPECT_EQ(zoomed_contents_bounds.CenterPoint().y(),
            (kCaretTop.y() + kCaretBottom.y()) / 2);
}

// Tests that the magnifier bounds are updated as a caret moves.
TEST_F(TouchSelectionMagnifierAuraTest, BoundsUpdate) {
  TouchSelectionMagnifierAura magnifier;
  Layer magnifier_parent;
  magnifier_parent.SetBounds(gfx::Rect(500, 400));

  // Show the magnifier at a caret.
  constexpr gfx::Point kCaretTop(300, 200);
  constexpr gfx::Point kCaretBottom(300, 210);
  magnifier.ShowFocusBound(&magnifier_parent, kCaretTop, kCaretBottom);
  // Move and resize the caret.
  constexpr gfx::Point kUpdatedCaretTop(310, 190);
  constexpr gfx::Point kUpdatedCaretBottom(310, 220);
  magnifier.ShowFocusBound(&magnifier_parent, kUpdatedCaretTop,
                           kUpdatedCaretBottom);

  // Magnifier should be horizontally centered above the caret.
  const gfx::Rect magnifier_bounds = magnifier.GetMagnifierBoundsForTesting();
  EXPECT_EQ(magnifier_bounds.CenterPoint().x(), kUpdatedCaretTop.x());
  EXPECT_LT(magnifier_bounds.bottom(), kUpdatedCaretBottom.y());

  // Zoomed content bounds should be centered on the caret.
  const gfx::Rect zoomed_contents_bounds =
      magnifier.GetZoomedContentsBoundsForTesting();
  EXPECT_EQ(zoomed_contents_bounds.CenterPoint().x(), kUpdatedCaretTop.x());
  EXPECT_EQ(zoomed_contents_bounds.CenterPoint().y(),
            (kUpdatedCaretTop.y() + kUpdatedCaretBottom.y()) / 2);
}

// Tests that the magnifier is adjusted to stay inside the parent layer when
// showing a caret close to the left edge of the parent.
TEST_F(TouchSelectionMagnifierAuraTest, StaysInsideParentLeftEdge) {
  TouchSelectionMagnifierAura magnifier;
  Layer magnifier_parent;
  constexpr gfx::Rect kParentBounds(500, 400);
  magnifier_parent.SetBounds(kParentBounds);

  // Show the magnifier at a caret near the left edge of the parent.
  magnifier.ShowFocusBound(&magnifier_parent, gfx::Point(10, 200),
                           gfx::Point(10, 210));

  // Magnifier (and what's zoomed) should be contained in the parent bounds.
  EXPECT_TRUE(kParentBounds.Contains(magnifier.GetMagnifierBoundsForTesting()));
  EXPECT_TRUE(
      kParentBounds.Contains(magnifier.GetZoomedContentsBoundsForTesting()));
}

// Tests that the magnifier is adjusted to stay inside the parent layer when
// showing a caret close to the right edge of the parent.
TEST_F(TouchSelectionMagnifierAuraTest, StaysInsideParentRightEdge) {
  TouchSelectionMagnifierAura magnifier;
  Layer magnifier_parent;
  constexpr gfx::Rect kParentBounds(500, 400);
  magnifier_parent.SetBounds(kParentBounds);

  // Show the magnifier at a caret near the right edge of the parent.
  magnifier.ShowFocusBound(&magnifier_parent, gfx::Point(495, 200),
                           gfx::Point(495, 210));

  // Magnifier (and what's zoomed) should be contained in the parent bounds.
  EXPECT_TRUE(kParentBounds.Contains(magnifier.GetMagnifierBoundsForTesting()));
  EXPECT_TRUE(
      kParentBounds.Contains(magnifier.GetZoomedContentsBoundsForTesting()));
}

// Tests that the magnifier is adjusted to stay inside the parent layer when
// showing a caret close to the top edge of the parent.
TEST_F(TouchSelectionMagnifierAuraTest, StaysInsideParentTopEdge) {
  TouchSelectionMagnifierAura magnifier;
  Layer magnifier_parent;
  constexpr gfx::Rect kParentBounds(500, 400);
  magnifier_parent.SetBounds(kParentBounds);

  // Show the magnifier at a caret near the top edge of the parent.
  magnifier.ShowFocusBound(&magnifier_parent, gfx::Point(200, 2),
                           gfx::Point(200, 12));

  // Magnifier (and what's zoomed) should be contained in the parent bounds.
  EXPECT_TRUE(kParentBounds.Contains(magnifier.GetMagnifierBoundsForTesting()));
  EXPECT_TRUE(
      kParentBounds.Contains(magnifier.GetZoomedContentsBoundsForTesting()));
}

// Tests that the magnifier remains the same size even at the edge of the
// parent layer.
TEST_F(TouchSelectionMagnifierAuraTest, Size) {
  TouchSelectionMagnifierAura magnifier;
  Layer magnifier_parent;
  magnifier_parent.SetBounds(gfx::Rect(500, 400));

  // Show magnifier.
  magnifier.ShowFocusBound(&magnifier_parent, gfx::Point(300, 200),
                           gfx::Point(300, 210));
  const gfx::Size magnifier_size =
      magnifier.GetMagnifierBoundsForTesting().size();
  const gfx::Size zoom_content_size =
      magnifier.GetZoomedContentsBoundsForTesting().size();
  // Move the caret near the edge of the parent container.
  magnifier.ShowFocusBound(&magnifier_parent, gfx::Point(10, 3),
                           gfx::Point(10, 13));

  // Magnifier should remain the same size.
  EXPECT_EQ(magnifier.GetMagnifierBoundsForTesting().size(), magnifier_size);
  EXPECT_EQ(magnifier.GetZoomedContentsBoundsForTesting().size(),
            zoom_content_size);
}

// Tests that the magnifier can be reparented to a different layer if needed.
TEST_F(TouchSelectionMagnifierAuraTest, SwitchesParentLayer) {
  TouchSelectionMagnifierAura magnifier;

  Layer magnifier_parent;
  magnifier_parent.SetBounds(gfx::Rect(500, 400));
  magnifier.ShowFocusBound(&magnifier_parent, gfx::Point(10, 20),
                           gfx::Point(10, 30));
  // Reparent the magnifier.
  Layer new_parent;
  new_parent.SetBounds(gfx::Rect(600, 400));
  magnifier.ShowFocusBound(&new_parent, gfx::Point(200, 20),
                           gfx::Point(200, 30));

  // Magnifier should have the updated parent.
  EXPECT_EQ(magnifier.GetMagnifierParentForTesting(), &new_parent);
}

}  // namespace

}  // namespace ui