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