• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TestBubbleFrameView()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   }
~TestBubbleFrameView()29   virtual ~TestBubbleFrameView() {}
30 
31   // BubbleFrameView overrides:
GetAvailableScreenBounds(const gfx::Rect & rect)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 
TEST_F(BubbleFrameViewTest,GetBoundsForClientView)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.
TEST_F(BubbleFrameViewTest,GetUpdatedWindowBounds)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.
TEST_F(BubbleFrameViewTest,GetUpdatedWindowBoundsMirroringFails)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 
TEST_F(BubbleFrameViewTest,TestMirroringForCenteredArrow)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.
TEST_F(BubbleFrameViewTest,GetUpdatedWindowBoundsDontTryMirror)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.
TEST_F(BubbleFrameViewTest,GetUpdatedWindowBoundsCenterArrows)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