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