| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/gfx/insets.h" |
| #include "ui/views/bubble/bubble_border.h" |
| #include "ui/views/bubble/bubble_frame_view.h" |
| #include "ui/views/test/views_test_base.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace views { |
| |
| typedef ViewsTestBase BubbleFrameViewTest; |
| |
| namespace { |
| |
| const BubbleBorder::Arrow kArrow = BubbleBorder::TOP_LEFT; |
| const SkColor kColor = SK_ColorRED; |
| const int kMargin = 6; |
| |
| class TestBubbleFrameView : public BubbleFrameView { |
| public: |
| TestBubbleFrameView() |
| : BubbleFrameView(gfx::Insets(kMargin, kMargin, kMargin, kMargin)), |
| monitor_bounds_(gfx::Rect(0, 0, 1000, 1000)) { |
| SetBubbleBorder(new BubbleBorder(kArrow, BubbleBorder::NO_SHADOW, kColor)); |
| } |
| virtual ~TestBubbleFrameView() {} |
| |
| // BubbleFrameView overrides: |
| virtual gfx::Rect GetMonitorBounds(const gfx::Rect& rect) OVERRIDE { |
| return monitor_bounds_; |
| } |
| |
| private: |
| gfx::Rect monitor_bounds_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestBubbleFrameView); |
| }; |
| |
| } // namespace |
| |
| TEST_F(BubbleFrameViewTest, GetBoundsForClientView) { |
| TestBubbleFrameView frame; |
| EXPECT_EQ(kArrow, frame.bubble_border()->arrow()); |
| EXPECT_EQ(kColor, frame.bubble_border()->background_color()); |
| |
| int margin_x = frame.content_margins().left(); |
| int margin_y = frame.content_margins().top(); |
| gfx::Insets insets = frame.bubble_border()->GetInsets(); |
| EXPECT_EQ(insets.left() + margin_x, frame.GetBoundsForClientView().x()); |
| EXPECT_EQ(insets.top() + margin_y, frame.GetBoundsForClientView().y()); |
| } |
| |
| // Tests that the arrow is mirrored as needed to better fit the screen. |
| TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { |
| TestBubbleFrameView frame; |
| gfx::Rect window_bounds; |
| |
| gfx::Insets insets = frame.bubble_border()->GetInsets(); |
| int xposition = 95 - insets.width(); |
| |
| // Test that the info bubble displays normally when it fits. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow()); |
| EXPECT_GT(window_bounds.x(), xposition); |
| EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for |
| // arrow overlap. |
| |
| // Test bubble not fitting on left. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_RIGHT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow()); |
| EXPECT_GT(window_bounds.x(), xposition); |
| EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for |
| // arrow overlap. |
| |
| // Test bubble not fitting on left or top. |
| frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_RIGHT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow()); |
| EXPECT_GT(window_bounds.x(), xposition); |
| EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for |
| // arrow overlap. |
| |
| // Test bubble not fitting on top. |
| frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_LEFT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow()); |
| EXPECT_GT(window_bounds.x(), xposition); |
| EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for |
| // arrow overlap. |
| |
| // Test bubble not fitting on top and right. |
| frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_LEFT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(900, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow()); |
| EXPECT_LT(window_bounds.x(), 900 + 50 - 500); |
| EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for |
| // arrow overlap. |
| |
| // Test bubble not fitting on right. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(900, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow()); |
| EXPECT_LT(window_bounds.x(), 900 + 50 - 500); |
| EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for |
| // arrow overlap. |
| |
| // Test bubble not fitting on bottom and right. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(900, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::BOTTOM_RIGHT, frame.bubble_border()->arrow()); |
| EXPECT_LT(window_bounds.x(), 900 + 50 - 500); |
| EXPECT_LT(window_bounds.y(), 900 - 500 - 15); // -15 to roughly compensate |
| // for arrow height. |
| |
| // Test bubble not fitting at the bottom. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::BOTTOM_LEFT, frame.bubble_border()->arrow()); |
| // The window should be right aligned with the anchor_rect. |
| EXPECT_LT(window_bounds.x(), 900 + 50 - 500); |
| EXPECT_LT(window_bounds.y(), 900 - 500 - 15); // -15 to roughly compensate |
| // for arrow height. |
| |
| // Test bubble not fitting at the bottom and left. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_RIGHT); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::BOTTOM_LEFT, frame.bubble_border()->arrow()); |
| // The window should be right aligned with the anchor_rect. |
| EXPECT_LT(window_bounds.x(), 900 + 50 - 500); |
| EXPECT_LT(window_bounds.y(), 900 - 500 - 15); // -15 to roughly compensate |
| // for arrow height. |
| } |
| |
| // Tests that the arrow is not moved when the info-bubble does not fit the |
| // screen but moving it would make matter worse. |
| TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsMirroringFails) { |
| TestBubbleFrameView frame; |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT); |
| gfx::Rect window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(400, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 700), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow()); |
| } |
| |
| TEST_F(BubbleFrameViewTest, TestMirroringForCenteredArrow) { |
| TestBubbleFrameView frame; |
| |
| // Test bubble not fitting above the anchor. |
| frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER); |
| gfx::Rect window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 700), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow()); |
| |
| // Test bubble not fitting below the anchor. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(300, 800, 50, 50), // |anchor_rect| |
| gfx::Size(500, 200), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow()); |
| |
| // Test bubble not fitting to the right of the anchor. |
| frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(800, 300, 50, 50), // |anchor_rect| |
| gfx::Size(200, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow()); |
| |
| // Test bubble not fitting to the left of the anchor. |
| frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 300, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow()); |
| } |
| |
| // Test that the arrow will not be mirrored when |adjust_if_offscreen| is false. |
| TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsDontTryMirror) { |
| TestBubbleFrameView frame; |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_RIGHT); |
| gfx::Rect window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| false); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow()); |
| // The coordinates should be pointing to anchor_rect from TOP_RIGHT. |
| EXPECT_LT(window_bounds.x(), 100 + 50 - 500); |
| EXPECT_GT(window_bounds.y(), 900 + 50 - 10); // -10 to roughly compensate for |
| // arrow overlap. |
| } |
| |
| // Test that the center arrow is moved as needed to fit the screen. |
| TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) { |
| TestBubbleFrameView frame; |
| gfx::Rect window_bounds; |
| |
| // Test that the bubble displays normally when it fits. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(500, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.x() + window_bounds.width() / 2, 525); |
| |
| frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(500, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.x() + window_bounds.width() / 2, 525); |
| |
| frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 400, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.y() + window_bounds.height() / 2, 425); |
| |
| frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(900, 400, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.y() + window_bounds.height() / 2, 425); |
| |
| // Test bubble not fitting left screen edge. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.x(), 0); |
| EXPECT_EQ(window_bounds.x() + |
| frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125); |
| |
| frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.x(), 0); |
| EXPECT_EQ(window_bounds.x() + |
| frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125); |
| |
| // Test bubble not fitting right screen edge. |
| frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(900, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.right(), 1000); |
| EXPECT_EQ(window_bounds.x() + |
| frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925); |
| |
| frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(900, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.right(), 1000); |
| EXPECT_EQ(window_bounds.x() + |
| frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925); |
| |
| // Test bubble not fitting top screen edge. |
| frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.y(), 0); |
| EXPECT_EQ(window_bounds.y() + |
| frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125); |
| |
| frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(900, 100, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.y(), 0); |
| EXPECT_EQ(window_bounds.y() + |
| frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125); |
| |
| // Test bubble not fitting bottom screen edge. |
| frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(100, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.bottom(), 1000); |
| EXPECT_EQ(window_bounds.y() + |
| frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925); |
| |
| frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER); |
| window_bounds = frame.GetUpdatedWindowBounds( |
| gfx::Rect(900, 900, 50, 50), // |anchor_rect| |
| gfx::Size(500, 500), // |client_size| |
| true); // |adjust_if_offscreen| |
| EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow()); |
| EXPECT_EQ(window_bounds.bottom(), 1000); |
| EXPECT_EQ(window_bounds.y() + |
| frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925); |
| } |
| |
| } // namespace views |