Home | History | Annotate | Download | only in bubble
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/gfx/insets.h"
      6 #include "ui/views/bubble/bubble_border.h"
      7 #include "ui/views/bubble/bubble_frame_view.h"
      8 #include "ui/views/test/views_test_base.h"
      9 #include "ui/views/widget/widget.h"
     10 
     11 namespace views {
     12 
     13 typedef ViewsTestBase BubbleFrameViewTest;
     14 
     15 namespace {
     16 
     17 const BubbleBorder::Arrow kArrow = BubbleBorder::TOP_LEFT;
     18 const SkColor kColor = SK_ColorRED;
     19 const int kMargin = 6;
     20 
     21 class TestBubbleFrameView : public BubbleFrameView {
     22  public:
     23   TestBubbleFrameView()
     24       : BubbleFrameView(gfx::Insets(kMargin, kMargin, kMargin, kMargin)),
     25         available_bounds_(gfx::Rect(0, 0, 1000, 1000)) {
     26     SetBubbleBorder(new BubbleBorder(kArrow, BubbleBorder::NO_SHADOW, kColor));
     27   }
     28   virtual ~TestBubbleFrameView() {}
     29 
     30   // BubbleFrameView overrides:
     31   virtual gfx::Rect GetAvailableScreenBounds(const gfx::Rect& rect) OVERRIDE {
     32     return available_bounds_;
     33   }
     34 
     35  private:
     36   gfx::Rect available_bounds_;
     37 
     38   DISALLOW_COPY_AND_ASSIGN(TestBubbleFrameView);
     39 };
     40 
     41 }  // namespace
     42 
     43 TEST_F(BubbleFrameViewTest, GetBoundsForClientView) {
     44   TestBubbleFrameView frame;
     45   EXPECT_EQ(kArrow, frame.bubble_border()->arrow());
     46   EXPECT_EQ(kColor, frame.bubble_border()->background_color());
     47 
     48   int margin_x = frame.content_margins().left();
     49   int margin_y = frame.content_margins().top();
     50   gfx::Insets insets = frame.bubble_border()->GetInsets();
     51   EXPECT_EQ(insets.left() + margin_x, frame.GetBoundsForClientView().x());
     52   EXPECT_EQ(insets.top() + margin_y, frame.GetBoundsForClientView().y());
     53 }
     54 
     55 // Tests that the arrow is mirrored as needed to better fit the screen.
     56 TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) {
     57   TestBubbleFrameView frame;
     58   gfx::Rect window_bounds;
     59 
     60   gfx::Insets insets = frame.bubble_border()->GetInsets();
     61   int xposition = 95 - insets.width();
     62 
     63   // Test that the info bubble displays normally when it fits.
     64   frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT);
     65   window_bounds = frame.GetUpdatedWindowBounds(
     66       gfx::Rect(100, 100, 50, 50),  // |anchor_rect|
     67       gfx::Size(500, 500),          // |client_size|
     68       true);                        // |adjust_if_offscreen|
     69   EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow());
     70   EXPECT_GT(window_bounds.x(), xposition);
     71   EXPECT_GT(window_bounds.y(), 100 + 50 - 10);  // -10 to roughly compensate for
     72                                                 // arrow overlap.
     73 
     74   // Test bubble not fitting on left.
     75   frame.bubble_border()->set_arrow(BubbleBorder::TOP_RIGHT);
     76   window_bounds = frame.GetUpdatedWindowBounds(
     77       gfx::Rect(100, 100, 50, 50),  // |anchor_rect|
     78       gfx::Size(500, 500),          // |client_size|
     79       true);                        // |adjust_if_offscreen|
     80   EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow());
     81   EXPECT_GT(window_bounds.x(), xposition);
     82   EXPECT_GT(window_bounds.y(), 100 + 50 - 10);  // -10 to roughly compensate for
     83                                                 // arrow overlap.
     84 
     85   // Test bubble not fitting on left or top.
     86   frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_RIGHT);
     87   window_bounds = frame.GetUpdatedWindowBounds(
     88       gfx::Rect(100, 100, 50, 50),  // |anchor_rect|
     89       gfx::Size(500, 500),          // |client_size|
     90       true);                        // |adjust_if_offscreen|
     91   EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow());
     92   EXPECT_GT(window_bounds.x(), xposition);
     93   EXPECT_GT(window_bounds.y(), 100 + 50 - 10);  // -10 to roughly compensate for
     94                                                 // arrow overlap.
     95 
     96   // Test bubble not fitting on top.
     97   frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_LEFT);
     98   window_bounds = frame.GetUpdatedWindowBounds(
     99       gfx::Rect(100, 100, 50, 50),  // |anchor_rect|
    100       gfx::Size(500, 500),          // |client_size|
    101       true);                        // |adjust_if_offscreen|
    102   EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow());
    103   EXPECT_GT(window_bounds.x(), xposition);
    104   EXPECT_GT(window_bounds.y(), 100 + 50 - 10);  // -10 to roughly compensate for
    105                                                 // arrow overlap.
    106 
    107   // Test bubble not fitting on top and right.
    108   frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_LEFT);
    109   window_bounds = frame.GetUpdatedWindowBounds(
    110       gfx::Rect(900, 100, 50, 50),  // |anchor_rect|
    111       gfx::Size(500, 500),          // |client_size|
    112       true);                        // |adjust_if_offscreen|
    113   EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow());
    114   EXPECT_LT(window_bounds.x(), 900 + 50 - 500);
    115   EXPECT_GT(window_bounds.y(), 100 + 50 - 10);  // -10 to roughly compensate for
    116                                                 // arrow overlap.
    117 
    118   // Test bubble not fitting on right.
    119   frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT);
    120   window_bounds = frame.GetUpdatedWindowBounds(
    121       gfx::Rect(900, 100, 50, 50),  // |anchor_rect|
    122       gfx::Size(500, 500),          // |client_size|
    123       true);                        // |adjust_if_offscreen|
    124   EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow());
    125   EXPECT_LT(window_bounds.x(), 900 + 50 - 500);
    126   EXPECT_GT(window_bounds.y(), 100 + 50 - 10);  // -10 to roughly compensate for
    127                                                 // arrow overlap.
    128 
    129   // Test bubble not fitting on bottom and right.
    130   frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT);
    131   window_bounds = frame.GetUpdatedWindowBounds(
    132       gfx::Rect(900, 900, 50, 50),  // |anchor_rect|
    133       gfx::Size(500, 500),          // |client_size|
    134       true);                        // |adjust_if_offscreen|
    135   EXPECT_EQ(BubbleBorder::BOTTOM_RIGHT, frame.bubble_border()->arrow());
    136   EXPECT_LT(window_bounds.x(), 900 + 50 - 500);
    137   EXPECT_LT(window_bounds.y(), 900 - 500 - 15);  // -15 to roughly compensate
    138                                                  // for arrow height.
    139 
    140   // Test bubble not fitting at the bottom.
    141   frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT);
    142   window_bounds = frame.GetUpdatedWindowBounds(
    143       gfx::Rect(100, 900, 50, 50),  // |anchor_rect|
    144       gfx::Size(500, 500),          // |client_size|
    145       true);                        // |adjust_if_offscreen|
    146   EXPECT_EQ(BubbleBorder::BOTTOM_LEFT, frame.bubble_border()->arrow());
    147   // The window should be right aligned with the anchor_rect.
    148   EXPECT_LT(window_bounds.x(), 900 + 50 - 500);
    149   EXPECT_LT(window_bounds.y(), 900 - 500 - 15);  // -15 to roughly compensate
    150                                                  // for arrow height.
    151 
    152   // Test bubble not fitting at the bottom and left.
    153   frame.bubble_border()->set_arrow(BubbleBorder::TOP_RIGHT);
    154   window_bounds = frame.GetUpdatedWindowBounds(
    155       gfx::Rect(100, 900, 50, 50),  // |anchor_rect|
    156       gfx::Size(500, 500),          // |client_size|
    157       true);                        // |adjust_if_offscreen|
    158   EXPECT_EQ(BubbleBorder::BOTTOM_LEFT, frame.bubble_border()->arrow());
    159   // The window should be right aligned with the anchor_rect.
    160   EXPECT_LT(window_bounds.x(), 900 + 50 - 500);
    161   EXPECT_LT(window_bounds.y(), 900 - 500 - 15);  // -15 to roughly compensate
    162                                                  // for arrow height.
    163 }
    164 
    165 // Tests that the arrow is not moved when the info-bubble does not fit the
    166 // screen but moving it would make matter worse.
    167 TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsMirroringFails) {
    168   TestBubbleFrameView frame;
    169   frame.bubble_border()->set_arrow(BubbleBorder::TOP_LEFT);
    170   gfx::Rect window_bounds = frame.GetUpdatedWindowBounds(
    171       gfx::Rect(400, 100, 50, 50),  // |anchor_rect|
    172       gfx::Size(500, 700),          // |client_size|
    173       true);                        // |adjust_if_offscreen|
    174   EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow());
    175 }
    176 
    177 TEST_F(BubbleFrameViewTest, TestMirroringForCenteredArrow) {
    178   TestBubbleFrameView frame;
    179 
    180   // Test bubble not fitting above the anchor.
    181   frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER);
    182   gfx::Rect window_bounds = frame.GetUpdatedWindowBounds(
    183       gfx::Rect(100, 100, 50, 50),  // |anchor_rect|
    184       gfx::Size(500, 700),          // |client_size|
    185       true);                        // |adjust_if_offscreen|
    186   EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow());
    187 
    188   // Test bubble not fitting below the anchor.
    189   frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER);
    190   window_bounds = frame.GetUpdatedWindowBounds(
    191       gfx::Rect(300, 800, 50, 50),  // |anchor_rect|
    192       gfx::Size(500, 200),          // |client_size|
    193       true);                        // |adjust_if_offscreen|
    194   EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow());
    195 
    196   // Test bubble not fitting to the right of the anchor.
    197   frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER);
    198   window_bounds = frame.GetUpdatedWindowBounds(
    199       gfx::Rect(800, 300, 50, 50),  // |anchor_rect|
    200       gfx::Size(200, 500),          // |client_size|
    201       true);                        // |adjust_if_offscreen|
    202   EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow());
    203 
    204   // Test bubble not fitting to the left of the anchor.
    205   frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER);
    206   window_bounds = frame.GetUpdatedWindowBounds(
    207       gfx::Rect(100, 300, 50, 50),  // |anchor_rect|
    208       gfx::Size(500, 500),          // |client_size|
    209       true);                        // |adjust_if_offscreen|
    210   EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow());
    211 }
    212 
    213 // Test that the arrow will not be mirrored when |adjust_if_offscreen| is false.
    214 TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsDontTryMirror) {
    215   TestBubbleFrameView frame;
    216   frame.bubble_border()->set_arrow(BubbleBorder::TOP_RIGHT);
    217   gfx::Rect window_bounds = frame.GetUpdatedWindowBounds(
    218       gfx::Rect(100, 900, 50, 50),  // |anchor_rect|
    219       gfx::Size(500, 500),          // |client_size|
    220       false);                       // |adjust_if_offscreen|
    221   EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow());
    222   // The coordinates should be pointing to anchor_rect from TOP_RIGHT.
    223   EXPECT_LT(window_bounds.x(), 100 + 50 - 500);
    224   EXPECT_GT(window_bounds.y(), 900 + 50 - 10);  // -10 to roughly compensate for
    225                                                 // arrow overlap.
    226 }
    227 
    228 // Test that the center arrow is moved as needed to fit the screen.
    229 TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) {
    230   TestBubbleFrameView frame;
    231   gfx::Rect window_bounds;
    232 
    233   // Test that the bubble displays normally when it fits.
    234   frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER);
    235   window_bounds = frame.GetUpdatedWindowBounds(
    236       gfx::Rect(500, 100, 50, 50),  // |anchor_rect|
    237       gfx::Size(500, 500),          // |client_size|
    238       true);                        // |adjust_if_offscreen|
    239   EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow());
    240   EXPECT_EQ(window_bounds.x() + window_bounds.width() / 2, 525);
    241 
    242   frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER);
    243   window_bounds = frame.GetUpdatedWindowBounds(
    244       gfx::Rect(500, 900, 50, 50),  // |anchor_rect|
    245       gfx::Size(500, 500),          // |client_size|
    246       true);                        // |adjust_if_offscreen|
    247   EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow());
    248   EXPECT_EQ(window_bounds.x() + window_bounds.width() / 2, 525);
    249 
    250   frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER);
    251   window_bounds = frame.GetUpdatedWindowBounds(
    252       gfx::Rect(100, 400, 50, 50),  // |anchor_rect|
    253       gfx::Size(500, 500),          // |client_size|
    254       true);                        // |adjust_if_offscreen|
    255   EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow());
    256   EXPECT_EQ(window_bounds.y() + window_bounds.height() / 2, 425);
    257 
    258   frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER);
    259   window_bounds = frame.GetUpdatedWindowBounds(
    260       gfx::Rect(900, 400, 50, 50),  // |anchor_rect|
    261       gfx::Size(500, 500),          // |client_size|
    262       true);                        // |adjust_if_offscreen|
    263   EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow());
    264   EXPECT_EQ(window_bounds.y() + window_bounds.height() / 2, 425);
    265 
    266   // Test bubble not fitting left screen edge.
    267   frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER);
    268   window_bounds = frame.GetUpdatedWindowBounds(
    269       gfx::Rect(100, 100, 50, 50),  // |anchor_rect|
    270       gfx::Size(500, 500),          // |client_size|
    271       true);                        // |adjust_if_offscreen|
    272   EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow());
    273   EXPECT_EQ(window_bounds.x(), 0);
    274   EXPECT_EQ(window_bounds.x() +
    275             frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125);
    276 
    277   frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER);
    278   window_bounds = frame.GetUpdatedWindowBounds(
    279       gfx::Rect(100, 900, 50, 50),  // |anchor_rect|
    280       gfx::Size(500, 500),          // |client_size|
    281       true);                        // |adjust_if_offscreen|
    282   EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow());
    283   EXPECT_EQ(window_bounds.x(), 0);
    284   EXPECT_EQ(window_bounds.x() +
    285             frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125);
    286 
    287   // Test bubble not fitting right screen edge.
    288   frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER);
    289   window_bounds = frame.GetUpdatedWindowBounds(
    290       gfx::Rect(900, 100, 50, 50),  // |anchor_rect|
    291       gfx::Size(500, 500),          // |client_size|
    292       true);                        // |adjust_if_offscreen|
    293   EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow());
    294   EXPECT_EQ(window_bounds.right(), 1000);
    295   EXPECT_EQ(window_bounds.x() +
    296             frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925);
    297 
    298   frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER);
    299   window_bounds = frame.GetUpdatedWindowBounds(
    300       gfx::Rect(900, 900, 50, 50),  // |anchor_rect|
    301       gfx::Size(500, 500),          // |client_size|
    302       true);                        // |adjust_if_offscreen|
    303   EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow());
    304   EXPECT_EQ(window_bounds.right(), 1000);
    305   EXPECT_EQ(window_bounds.x() +
    306             frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925);
    307 
    308   // Test bubble not fitting top screen edge.
    309   frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER);
    310   window_bounds = frame.GetUpdatedWindowBounds(
    311       gfx::Rect(100, 100, 50, 50),  // |anchor_rect|
    312       gfx::Size(500, 500),          // |client_size|
    313       true);                        // |adjust_if_offscreen|
    314   EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow());
    315   EXPECT_EQ(window_bounds.y(), 0);
    316   EXPECT_EQ(window_bounds.y() +
    317             frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125);
    318 
    319   frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER);
    320   window_bounds = frame.GetUpdatedWindowBounds(
    321       gfx::Rect(900, 100, 50, 50),  // |anchor_rect|
    322       gfx::Size(500, 500),          // |client_size|
    323       true);                        // |adjust_if_offscreen|
    324   EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow());
    325   EXPECT_EQ(window_bounds.y(), 0);
    326   EXPECT_EQ(window_bounds.y() +
    327             frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125);
    328 
    329   // Test bubble not fitting bottom screen edge.
    330   frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER);
    331   window_bounds = frame.GetUpdatedWindowBounds(
    332       gfx::Rect(100, 900, 50, 50),  // |anchor_rect|
    333       gfx::Size(500, 500),          // |client_size|
    334       true);                        // |adjust_if_offscreen|
    335   EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow());
    336   EXPECT_EQ(window_bounds.bottom(), 1000);
    337   EXPECT_EQ(window_bounds.y() +
    338             frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925);
    339 
    340   frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER);
    341   window_bounds = frame.GetUpdatedWindowBounds(
    342       gfx::Rect(900, 900, 50, 50),  // |anchor_rect|
    343       gfx::Size(500, 500),          // |client_size|
    344       true);                        // |adjust_if_offscreen|
    345   EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow());
    346   EXPECT_EQ(window_bounds.bottom(), 1000);
    347   EXPECT_EQ(window_bounds.y() +
    348             frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925);
    349 }
    350 
    351 }  // namespace views
    352