Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(268)

Side by Side Diff: chrome/browser/ui/views/tabs/tab.cc

Issue 1477713002: Paint tab-loading throbbers into a ui::Layer (reland). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase for r362326 and r362195 conflicts Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.h ('k') | chrome/browser/ui/views/tabs/tab_controller.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.h ('k') | chrome/browser/ui/views/tabs/tab_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698