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 11namespace views { 12 13typedef ViewsTestBase BubbleFrameViewTest; 14 15namespace { 16 17const BubbleBorder::Arrow kArrow = BubbleBorder::TOP_LEFT; 18const SkColor kColor = SK_ColorRED; 19const int kMargin = 6; 20 21class 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 44TEST_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. 57TEST_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. 168TEST_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 178TEST_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. 215TEST_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. 230TEST_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