OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/tabs/tab.h" | 5 #include "chrome/browser/ui/views/tabs/tab.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/debug/alias.h" | 10 #include "base/debug/alias.h" |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 | 344 |
345 return MaskedTargeterDelegate::DoesIntersectRect(target, rect); | 345 return MaskedTargeterDelegate::DoesIntersectRect(target, rect); |
346 } | 346 } |
347 | 347 |
348 Tab* tab_; | 348 Tab* tab_; |
349 | 349 |
350 DISALLOW_COPY_AND_ASSIGN(TabCloseButton); | 350 DISALLOW_COPY_AND_ASSIGN(TabCloseButton); |
351 }; | 351 }; |
352 | 352 |
353 //////////////////////////////////////////////////////////////////////////////// | 353 //////////////////////////////////////////////////////////////////////////////// |
| 354 // ThrobberView |
| 355 // |
| 356 // A Layer-backed view for updating a waiting or loading tab throbber. |
| 357 class Tab::ThrobberView : public views::View { |
| 358 public: |
| 359 explicit ThrobberView(Tab* owner); |
| 360 |
| 361 // Resets the times tracking when the throbber changes state. |
| 362 void ResetStartTimes(); |
| 363 |
| 364 private: |
| 365 // views::View: |
| 366 bool CanProcessEventsWithinSubtree() const override; |
| 367 void OnPaint(gfx::Canvas* canvas) override; |
| 368 |
| 369 Tab* owner_; // Weak. Owns |this|. |
| 370 |
| 371 // The point in time when the tab icon was first painted in the waiting state. |
| 372 base::TimeTicks waiting_start_time_; |
| 373 |
| 374 // The point in time when the tab icon was first painted in the loading state. |
| 375 base::TimeTicks loading_start_time_; |
| 376 |
| 377 // Paint state for the throbber after the most recent waiting paint. |
| 378 gfx::ThrobberWaitingState waiting_state_; |
| 379 |
| 380 DISALLOW_COPY_AND_ASSIGN(ThrobberView); |
| 381 }; |
| 382 |
| 383 Tab::ThrobberView::ThrobberView(Tab* owner) : owner_(owner) {} |
| 384 |
| 385 void Tab::ThrobberView::ResetStartTimes() { |
| 386 waiting_start_time_ = base::TimeTicks(); |
| 387 loading_start_time_ = base::TimeTicks(); |
| 388 waiting_state_ = gfx::ThrobberWaitingState(); |
| 389 } |
| 390 |
| 391 bool Tab::ThrobberView::CanProcessEventsWithinSubtree() const { |
| 392 return false; |
| 393 } |
| 394 |
| 395 void Tab::ThrobberView::OnPaint(gfx::Canvas* canvas) { |
| 396 const TabRendererData::NetworkState state = owner_->data().network_state; |
| 397 if (state == TabRendererData::NETWORK_STATE_NONE) |
| 398 return; |
| 399 |
| 400 const ui::ThemeProvider* tp = GetThemeProvider(); |
| 401 const gfx::Rect bounds = GetLocalBounds(); |
| 402 if (state == TabRendererData::NETWORK_STATE_WAITING) { |
| 403 if (waiting_start_time_ == base::TimeTicks()) |
| 404 waiting_start_time_ = base::TimeTicks::Now(); |
| 405 |
| 406 waiting_state_.elapsed_time = base::TimeTicks::Now() - waiting_start_time_; |
| 407 gfx::PaintThrobberWaiting( |
| 408 canvas, bounds, |
| 409 tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_WAITING), |
| 410 waiting_state_.elapsed_time); |
| 411 } else { |
| 412 if (loading_start_time_ == base::TimeTicks()) |
| 413 loading_start_time_ = base::TimeTicks::Now(); |
| 414 |
| 415 waiting_state_.color = |
| 416 tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_WAITING); |
| 417 gfx::PaintThrobberSpinningAfterWaiting( |
| 418 canvas, bounds, |
| 419 tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_SPINNING), |
| 420 base::TimeTicks::Now() - loading_start_time_, &waiting_state_); |
| 421 } |
| 422 } |
| 423 |
| 424 //////////////////////////////////////////////////////////////////////////////// |
354 // ImageCacheEntry | 425 // ImageCacheEntry |
355 | 426 |
356 Tab::ImageCacheEntry::ImageCacheEntry() | 427 Tab::ImageCacheEntry::ImageCacheEntry() |
357 : resource_id(-1), | 428 : resource_id(-1), |
358 scale_factor(ui::SCALE_FACTOR_NONE) { | 429 scale_factor(ui::SCALE_FACTOR_NONE) { |
359 } | 430 } |
360 | 431 |
361 Tab::ImageCacheEntry::~ImageCacheEntry() {} | 432 Tab::ImageCacheEntry::~ImageCacheEntry() {} |
362 | 433 |
363 //////////////////////////////////////////////////////////////////////////////// | 434 //////////////////////////////////////////////////////////////////////////////// |
(...skipping 10 matching lines...) Expand all Loading... |
374 // Tab, public: | 445 // Tab, public: |
375 | 446 |
376 Tab::Tab(TabController* controller) | 447 Tab::Tab(TabController* controller) |
377 : controller_(controller), | 448 : controller_(controller), |
378 closing_(false), | 449 closing_(false), |
379 dragging_(false), | 450 dragging_(false), |
380 detached_(false), | 451 detached_(false), |
381 favicon_hiding_offset_(0), | 452 favicon_hiding_offset_(0), |
382 immersive_loading_step_(0), | 453 immersive_loading_step_(0), |
383 should_display_crashed_favicon_(false), | 454 should_display_crashed_favicon_(false), |
| 455 throbber_(nullptr), |
384 media_indicator_button_(nullptr), | 456 media_indicator_button_(nullptr), |
385 close_button_(nullptr), | 457 close_button_(nullptr), |
386 title_(new views::Label()), | 458 title_(new views::Label()), |
387 tab_activated_with_last_tap_down_(false), | 459 tab_activated_with_last_tap_down_(false), |
388 hover_controller_(this), | 460 hover_controller_(this), |
389 showing_icon_(false), | 461 showing_icon_(false), |
390 showing_media_indicator_(false), | 462 showing_media_indicator_(false), |
391 showing_close_button_(false), | 463 showing_close_button_(false), |
392 button_color_(SK_ColorTRANSPARENT) { | 464 button_color_(SK_ColorTRANSPARENT) { |
393 DCHECK(controller); | 465 DCHECK(controller); |
(...skipping 10 matching lines...) Expand all Loading... |
404 title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD); | 476 title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD); |
405 title_->SetElideBehavior(gfx::FADE_TAIL); | 477 title_->SetElideBehavior(gfx::FADE_TAIL); |
406 title_->SetHandlesTooltips(false); | 478 title_->SetHandlesTooltips(false); |
407 title_->SetAutoColorReadabilityEnabled(false); | 479 title_->SetAutoColorReadabilityEnabled(false); |
408 title_->SetText(CoreTabHelper::GetDefaultTitle()); | 480 title_->SetText(CoreTabHelper::GetDefaultTitle()); |
409 AddChildView(title_); | 481 AddChildView(title_); |
410 | 482 |
411 SetEventTargeter( | 483 SetEventTargeter( |
412 scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); | 484 scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); |
413 | 485 |
| 486 throbber_ = new ThrobberView(this); |
| 487 throbber_->SetVisible(false); |
| 488 AddChildView(throbber_); |
| 489 |
414 media_indicator_button_ = new MediaIndicatorButton(this); | 490 media_indicator_button_ = new MediaIndicatorButton(this); |
415 AddChildView(media_indicator_button_); | 491 AddChildView(media_indicator_button_); |
416 | 492 |
417 close_button_ = new TabCloseButton(this); | 493 close_button_ = new TabCloseButton(this); |
418 close_button_->SetAccessibleName( | 494 close_button_->SetAccessibleName( |
419 l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); | 495 l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); |
420 // The normal image is set by OnButtonColorMaybeChanged() because it depends | 496 // The normal image is set by OnButtonColorMaybeChanged() because it depends |
421 // on the current theme and active state. The hovered and pressed images | 497 // on the current theme and active state. The hovered and pressed images |
422 // don't depend on the these, so we can set them here. | 498 // don't depend on the these, so we can set them here. |
423 const gfx::ImageSkia& hovered = gfx::CreateVectorIcon( | 499 const gfx::ImageSkia& hovered = gfx::CreateVectorIcon( |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 return controller_->IsTabSelected(this); | 534 return controller_->IsTabSelected(this); |
459 } | 535 } |
460 | 536 |
461 void Tab::SetData(const TabRendererData& data) { | 537 void Tab::SetData(const TabRendererData& data) { |
462 DCHECK(GetWidget()); | 538 DCHECK(GetWidget()); |
463 | 539 |
464 if (data_.Equals(data)) | 540 if (data_.Equals(data)) |
465 return; | 541 return; |
466 | 542 |
467 TabRendererData old(data_); | 543 TabRendererData old(data_); |
| 544 UpdateLoadingAnimation(data.network_state); |
468 data_ = data; | 545 data_ = data; |
469 | 546 |
470 base::string16 title = data_.title; | 547 base::string16 title = data_.title; |
471 if (title.empty()) { | 548 if (title.empty()) { |
472 title = data_.loading ? | 549 title = data_.loading ? |
473 l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) : | 550 l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) : |
474 CoreTabHelper::GetDefaultTitle(); | 551 CoreTabHelper::GetDefaultTitle(); |
475 } else { | 552 } else { |
476 Browser::FormatTitleForDisplay(&title); | 553 Browser::FormatTitleForDisplay(&title); |
477 } | 554 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 } | 594 } |
518 | 595 |
519 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { | 596 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { |
520 if (state == data_.network_state && | 597 if (state == data_.network_state && |
521 state == TabRendererData::NETWORK_STATE_NONE) { | 598 state == TabRendererData::NETWORK_STATE_NONE) { |
522 // If the network state is none and hasn't changed, do nothing. Otherwise we | 599 // If the network state is none and hasn't changed, do nothing. Otherwise we |
523 // need to advance the animation frame. | 600 // need to advance the animation frame. |
524 return; | 601 return; |
525 } | 602 } |
526 | 603 |
527 TabRendererData::NetworkState old_state = data_.network_state; | |
528 data_.network_state = state; | 604 data_.network_state = state; |
529 AdvanceLoadingAnimation(old_state, state); | 605 AdvanceLoadingAnimation(); |
530 } | 606 } |
531 | 607 |
532 void Tab::StartPulse() { | 608 void Tab::StartPulse() { |
533 pulse_animation_.reset(new gfx::ThrobAnimation(this)); | 609 pulse_animation_.reset(new gfx::ThrobAnimation(this)); |
534 pulse_animation_->SetSlideDuration(kPulseDurationMs); | 610 pulse_animation_->SetSlideDuration(kPulseDurationMs); |
535 if (animation_container_.get()) | 611 if (animation_container_.get()) |
536 pulse_animation_->SetContainer(animation_container_.get()); | 612 pulse_animation_->SetContainer(animation_container_.get()); |
537 pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); | 613 pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); |
538 } | 614 } |
539 | 615 |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
808 const int extra_padding = | 884 const int extra_padding = |
809 (controller_->ShouldHideCloseButtonForInactiveTabs() || | 885 (controller_->ShouldHideCloseButtonForInactiveTabs() || |
810 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; | 886 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; |
811 const int start = lb.x() + extra_padding; | 887 const int start = lb.x() + extra_padding; |
812 favicon_bounds_.SetRect(start, lb.y(), 0, 0); | 888 favicon_bounds_.SetRect(start, lb.y(), 0, 0); |
813 if (showing_icon_) { | 889 if (showing_icon_) { |
814 favicon_bounds_.set_size(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize)); | 890 favicon_bounds_.set_size(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize)); |
815 favicon_bounds_.set_y(lb.y() + (lb.height() - gfx::kFaviconSize + 1) / 2); | 891 favicon_bounds_.set_y(lb.y() + (lb.height() - gfx::kFaviconSize + 1) / 2); |
816 MaybeAdjustLeftForPinnedTab(&favicon_bounds_); | 892 MaybeAdjustLeftForPinnedTab(&favicon_bounds_); |
817 } | 893 } |
| 894 throbber_->SetBoundsRect(favicon_bounds_); |
818 | 895 |
819 showing_close_button_ = ShouldShowCloseBox(); | 896 showing_close_button_ = ShouldShowCloseBox(); |
820 if (showing_close_button_) { | 897 if (showing_close_button_) { |
821 // If the ratio of the close button size to tab width exceeds the maximum. | 898 // If the ratio of the close button size to tab width exceeds the maximum. |
822 // The close button should be as large as possible so that there is a larger | 899 // The close button should be as large as possible so that there is a larger |
823 // hit-target for touch events. So the close button bounds extends to the | 900 // hit-target for touch events. So the close button bounds extends to the |
824 // edges of the tab. However, the larger hit-target should be active only | 901 // edges of the tab. However, the larger hit-target should be active only |
825 // for mouse events, and the close-image should show up in the right place. | 902 // for mouse events, and the close-image should show up in the right place. |
826 // So a border is added to the button with necessary padding. The close | 903 // So a border is added to the button with necessary padding. The close |
827 // button (BaseTab::TabCloseButton) makes sure the padding is a hit-target | 904 // button (BaseTab::TabCloseButton) makes sure the padding is a hit-target |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1308 | 1385 |
1309 void Tab::PaintIcon(gfx::Canvas* canvas) { | 1386 void Tab::PaintIcon(gfx::Canvas* canvas) { |
1310 gfx::Rect bounds = favicon_bounds_; | 1387 gfx::Rect bounds = favicon_bounds_; |
1311 bounds.set_x(GetMirroredXForRect(bounds)); | 1388 bounds.set_x(GetMirroredXForRect(bounds)); |
1312 bounds.Offset(0, favicon_hiding_offset_); | 1389 bounds.Offset(0, favicon_hiding_offset_); |
1313 bounds.Intersect(GetContentsBounds()); | 1390 bounds.Intersect(GetContentsBounds()); |
1314 if (bounds.IsEmpty()) | 1391 if (bounds.IsEmpty()) |
1315 return; | 1392 return; |
1316 | 1393 |
1317 if (data().network_state != TabRendererData::NETWORK_STATE_NONE) { | 1394 if (data().network_state != TabRendererData::NETWORK_STATE_NONE) { |
1318 // Paint network activity (aka throbber) animation frame. | 1395 // Throbber will do its own painting. |
1319 const ui::ThemeProvider* tp = GetThemeProvider(); | |
1320 if (data().network_state == TabRendererData::NETWORK_STATE_WAITING) { | |
1321 if (waiting_start_time_ == base::TimeTicks()) | |
1322 waiting_start_time_ = base::TimeTicks::Now(); | |
1323 | |
1324 waiting_state_.elapsed_time = | |
1325 base::TimeTicks::Now() - waiting_start_time_; | |
1326 gfx::PaintThrobberWaiting( | |
1327 canvas, bounds, | |
1328 tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_WAITING), | |
1329 waiting_state_.elapsed_time); | |
1330 } else { | |
1331 if (loading_start_time_ == base::TimeTicks()) | |
1332 loading_start_time_ = base::TimeTicks::Now(); | |
1333 | |
1334 waiting_state_.color = | |
1335 tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_WAITING); | |
1336 gfx::PaintThrobberSpinningAfterWaiting( | |
1337 canvas, bounds, | |
1338 tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_SPINNING), | |
1339 base::TimeTicks::Now() - loading_start_time_, &waiting_state_); | |
1340 } | |
1341 } else { | 1396 } else { |
1342 const gfx::ImageSkia& favicon = should_display_crashed_favicon_ ? | 1397 const gfx::ImageSkia& favicon = should_display_crashed_favicon_ ? |
1343 *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( | 1398 *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
1344 IDR_CRASH_SAD_FAVICON) : | 1399 IDR_CRASH_SAD_FAVICON) : |
1345 data().favicon; | 1400 data().favicon; |
1346 if (!favicon.isNull()) { | 1401 if (!favicon.isNull()) { |
1347 canvas->DrawImageInt(favicon, 0, 0, bounds.width(), bounds.height(), | 1402 canvas->DrawImageInt(favicon, 0, 0, bounds.width(), bounds.height(), |
1348 bounds.x(), bounds.y(), bounds.width(), | 1403 bounds.x(), bounds.y(), bounds.width(), |
1349 bounds.height(), false); | 1404 bounds.height(), false); |
1350 } | 1405 } |
1351 } | 1406 } |
1352 } | 1407 } |
1353 | 1408 |
1354 void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, | 1409 void Tab::AdvanceLoadingAnimation() { |
1355 TabRendererData::NetworkState state) { | 1410 const TabRendererData::NetworkState state = data().network_state; |
1356 if (state == TabRendererData::NETWORK_STATE_WAITING) { | 1411 if (controller_->IsImmersiveStyle()) { |
1357 // Waiting steps backwards. | 1412 if (state == TabRendererData::NETWORK_STATE_WAITING) { |
1358 immersive_loading_step_ = | 1413 // Waiting steps backwards. |
1359 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % | 1414 immersive_loading_step_ = |
1360 kImmersiveLoadingStepCount; | 1415 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % |
1361 } else if (state == TabRendererData::NETWORK_STATE_LOADING) { | 1416 kImmersiveLoadingStepCount; |
1362 immersive_loading_step_ = (immersive_loading_step_ + 1) % | 1417 } else if (state == TabRendererData::NETWORK_STATE_LOADING) { |
1363 kImmersiveLoadingStepCount; | 1418 immersive_loading_step_ = |
1364 } else { | 1419 (immersive_loading_step_ + 1) % kImmersiveLoadingStepCount; |
1365 waiting_start_time_ = base::TimeTicks(); | 1420 } else { |
1366 loading_start_time_ = base::TimeTicks(); | 1421 immersive_loading_step_ = 0; |
1367 waiting_state_ = gfx::ThrobberWaitingState(); | 1422 } |
1368 immersive_loading_step_ = 0; | 1423 |
| 1424 SchedulePaintInRect(GetImmersiveBarRect()); |
| 1425 return; |
1369 } | 1426 } |
1370 if (controller_->IsImmersiveStyle()) { | 1427 |
1371 SchedulePaintInRect(GetImmersiveBarRect()); | 1428 if (state == TabRendererData::NETWORK_STATE_NONE) { |
1372 } else { | 1429 throbber_->ResetStartTimes(); |
| 1430 throbber_->SetVisible(false); |
1373 ScheduleIconPaint(); | 1431 ScheduleIconPaint(); |
| 1432 return; |
1374 } | 1433 } |
| 1434 |
| 1435 // Since the throbber can animate for a long time, paint to a separate layer |
| 1436 // when possible to reduce repaint overhead. |
| 1437 const bool paint_to_layer = controller_->CanPaintThrobberToLayer(); |
| 1438 if (paint_to_layer != !!throbber_->layer()) { |
| 1439 throbber_->SetPaintToLayer(paint_to_layer); |
| 1440 throbber_->SetFillsBoundsOpaquely(false); |
| 1441 if (paint_to_layer) |
| 1442 ScheduleIconPaint(); // Ensure the non-layered throbber goes away. |
| 1443 } |
| 1444 if (!throbber_->visible()) { |
| 1445 ScheduleIconPaint(); // Repaint the icon area to hide the favicon. |
| 1446 throbber_->SetVisible(true); |
| 1447 } |
| 1448 throbber_->SchedulePaint(); |
1375 } | 1449 } |
1376 | 1450 |
1377 int Tab::IconCapacity() const { | 1451 int Tab::IconCapacity() const { |
1378 const gfx::Size min_size(GetMinimumInactiveSize()); | 1452 const gfx::Size min_size(GetMinimumInactiveSize()); |
1379 if (height() < min_size.height()) | 1453 if (height() < min_size.height()) |
1380 return 0; | 1454 return 0; |
1381 const int available_width = std::max(0, width() - min_size.width()); | 1455 const int available_width = std::max(0, width() - min_size.width()); |
1382 // All icons are the same size as the favicon. | 1456 // All icons are the same size as the favicon. |
1383 const int icon_width = gfx::kFaviconSize; | 1457 const int icon_width = gfx::kFaviconSize; |
1384 // We need enough space to display the icons flush against each other. | 1458 // We need enough space to display the icons flush against each other. |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1556 const gfx::ImageSkia& image) { | 1630 const gfx::ImageSkia& image) { |
1557 DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE); | 1631 DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE); |
1558 ImageCacheEntry entry; | 1632 ImageCacheEntry entry; |
1559 entry.resource_id = resource_id; | 1633 entry.resource_id = resource_id; |
1560 entry.scale_factor = scale_factor; | 1634 entry.scale_factor = scale_factor; |
1561 entry.image = image; | 1635 entry.image = image; |
1562 image_cache_->push_front(entry); | 1636 image_cache_->push_front(entry); |
1563 if (image_cache_->size() > kMaxImageCacheSize) | 1637 if (image_cache_->size() > kMaxImageCacheSize) |
1564 image_cache_->pop_back(); | 1638 image_cache_->pop_back(); |
1565 } | 1639 } |
OLD | NEW |