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 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
130 // The minimum opacity (out of 1) when a tab (either active or inactive) is | 130 // The minimum opacity (out of 1) when a tab (either active or inactive) is |
131 // throbbing in the immersive mode light strip. | 131 // throbbing in the immersive mode light strip. |
132 const double kImmersiveTabMinThrobOpacity = 0.66; | 132 const double kImmersiveTabMinThrobOpacity = 0.66; |
133 | 133 |
134 // Number of steps in the immersive mode loading animation. | 134 // Number of steps in the immersive mode loading animation. |
135 const int kImmersiveLoadingStepCount = 32; | 135 const int kImmersiveLoadingStepCount = 32; |
136 | 136 |
137 const char kTabCloseButtonName[] = "TabCloseButton"; | 137 const char kTabCloseButtonName[] = "TabCloseButton"; |
138 const int kTabCloseButtonSize = 16; | 138 const int kTabCloseButtonSize = 16; |
139 | 139 |
140 // Layer-backed view for updating a waiting or loading tab spinner. | |
141 class ThrobberView : public views::View { | |
142 public: | |
143 ThrobberView(Tab* owner, const gfx::Rect& bounds) : owner_(owner) { | |
144 SetPaintToLayer(true); | |
danakj
2015/10/08 14:09:01
Can you leave a comment that this paints to separa
tapted
2015/10/09 06:39:02
Done.
| |
145 SetFillsBoundsOpaquely(false); | |
146 SetBoundsRect(bounds); | |
147 owner_->AddChildView(this); | |
148 } | |
149 | |
150 // views::View: | |
151 void OnPaint(gfx::Canvas* canvas) override { | |
152 const TabRendererData::NetworkState state = owner_->data().network_state; | |
153 if (state == TabRendererData::NETWORK_STATE_NONE) | |
154 return; | |
155 | |
156 const gfx::Rect bounds = GetLocalBounds(); | |
157 | |
158 // Paint network activity (aka throbber) animation frame. | |
159 ui::ThemeProvider* tp = owner_->GetThemeProvider(); | |
sky
2015/10/08 15:52:23
Do you really need owner_ here?
tapted
2015/10/09 06:39:02
Whoops - removed.
| |
160 if (state == TabRendererData::NETWORK_STATE_WAITING) { | |
161 if (waiting_start_time_ == base::TimeTicks()) | |
162 waiting_start_time_ = base::TimeTicks::Now(); | |
163 | |
164 waiting_state_.elapsed_time = | |
165 base::TimeTicks::Now() - waiting_start_time_; | |
166 gfx::PaintThrobberWaiting( | |
167 canvas, bounds, tp->GetColor(ThemeProperties::COLOR_THROBBER_WAITING), | |
168 waiting_state_.elapsed_time); | |
169 } else { | |
170 if (loading_start_time_ == base::TimeTicks()) | |
171 loading_start_time_ = base::TimeTicks::Now(); | |
172 | |
173 waiting_state_.color = | |
174 tp->GetColor(ThemeProperties::COLOR_THROBBER_WAITING); | |
175 gfx::PaintThrobberSpinningAfterWaiting( | |
176 canvas, bounds, | |
177 tp->GetColor(ThemeProperties::COLOR_THROBBER_SPINNING), | |
178 base::TimeTicks::Now() - loading_start_time_, &waiting_state_); | |
179 } | |
180 } | |
181 | |
182 private: | |
183 Tab* owner_; // Weak. Owns this. | |
danakj
2015/10/08 14:09:01
"Owns this" can be a bit ambiguous. "Owns |this|"?
tapted
2015/10/09 06:39:02
Done.
| |
184 | |
185 // The point in time when the tab icon was first painted in the waiting state. | |
186 base::TimeTicks waiting_start_time_; | |
187 | |
188 // The point in time when the tab icon was first painted in the loading state. | |
189 base::TimeTicks loading_start_time_; | |
190 | |
191 // Paint state for the throbber after the most recent waiting paint. | |
192 gfx::ThrobberWaitingState waiting_state_; | |
193 | |
194 DISALLOW_COPY_AND_ASSIGN(ThrobberView); | |
195 }; | |
196 | |
140 void DrawIconAtLocation(gfx::Canvas* canvas, | 197 void DrawIconAtLocation(gfx::Canvas* canvas, |
141 const gfx::ImageSkia& image, | 198 const gfx::ImageSkia& image, |
142 int image_offset, | 199 int image_offset, |
143 int dst_x, | 200 int dst_x, |
144 int dst_y, | 201 int dst_y, |
145 int icon_width, | 202 int icon_width, |
146 int icon_height, | 203 int icon_height, |
147 bool filter, | 204 bool filter, |
148 const SkPaint& paint) { | 205 const SkPaint& paint) { |
149 // NOTE: the clipping is a work around for 69528, it shouldn't be necessary. | 206 // NOTE: the clipping is a work around for 69528, it shouldn't be necessary. |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
405 // Tab, public: | 462 // Tab, public: |
406 | 463 |
407 Tab::Tab(TabController* controller) | 464 Tab::Tab(TabController* controller) |
408 : controller_(controller), | 465 : controller_(controller), |
409 closing_(false), | 466 closing_(false), |
410 dragging_(false), | 467 dragging_(false), |
411 detached_(false), | 468 detached_(false), |
412 favicon_hiding_offset_(0), | 469 favicon_hiding_offset_(0), |
413 immersive_loading_step_(0), | 470 immersive_loading_step_(0), |
414 should_display_crashed_favicon_(false), | 471 should_display_crashed_favicon_(false), |
472 throbber_(nullptr), | |
415 media_indicator_button_(nullptr), | 473 media_indicator_button_(nullptr), |
416 close_button_(nullptr), | 474 close_button_(nullptr), |
417 title_(new views::Label()), | 475 title_(new views::Label()), |
418 tab_activated_with_last_tap_down_(false), | 476 tab_activated_with_last_tap_down_(false), |
419 hover_controller_(this), | 477 hover_controller_(this), |
420 showing_icon_(false), | 478 showing_icon_(false), |
421 showing_media_indicator_(false), | 479 showing_media_indicator_(false), |
422 showing_close_button_(false), | 480 showing_close_button_(false), |
423 button_color_(SK_ColorTRANSPARENT) { | 481 button_color_(SK_ColorTRANSPARENT) { |
424 DCHECK(controller); | 482 DCHECK(controller); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
545 } | 603 } |
546 | 604 |
547 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { | 605 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { |
548 if (state == data_.network_state && | 606 if (state == data_.network_state && |
549 state == TabRendererData::NETWORK_STATE_NONE) { | 607 state == TabRendererData::NETWORK_STATE_NONE) { |
550 // If the network state is none and hasn't changed, do nothing. Otherwise we | 608 // If the network state is none and hasn't changed, do nothing. Otherwise we |
551 // need to advance the animation frame. | 609 // need to advance the animation frame. |
552 return; | 610 return; |
553 } | 611 } |
554 | 612 |
555 TabRendererData::NetworkState old_state = data_.network_state; | |
556 data_.network_state = state; | 613 data_.network_state = state; |
557 AdvanceLoadingAnimation(old_state, state); | 614 AdvanceLoadingAnimation(state); |
558 } | 615 } |
559 | 616 |
560 void Tab::StartPulse() { | 617 void Tab::StartPulse() { |
561 pulse_animation_.reset(new gfx::ThrobAnimation(this)); | 618 pulse_animation_.reset(new gfx::ThrobAnimation(this)); |
562 pulse_animation_->SetSlideDuration(kPulseDurationMs); | 619 pulse_animation_->SetSlideDuration(kPulseDurationMs); |
563 if (animation_container_.get()) | 620 if (animation_container_.get()) |
564 pulse_animation_->SetContainer(animation_container_.get()); | 621 pulse_animation_->SetContainer(animation_container_.get()); |
565 pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); | 622 pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); |
566 } | 623 } |
567 | 624 |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
780 const int extra_padding = | 837 const int extra_padding = |
781 (controller_->ShouldHideCloseButtonForInactiveTabs() || | 838 (controller_->ShouldHideCloseButtonForInactiveTabs() || |
782 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; | 839 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; |
783 const int start = lb.x() + extra_padding; | 840 const int start = lb.x() + extra_padding; |
784 favicon_bounds_.SetRect(start, lb.y(), 0, 0); | 841 favicon_bounds_.SetRect(start, lb.y(), 0, 0); |
785 if (showing_icon_) { | 842 if (showing_icon_) { |
786 favicon_bounds_.set_size(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize)); | 843 favicon_bounds_.set_size(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize)); |
787 favicon_bounds_.set_y(lb.y() + (lb.height() - gfx::kFaviconSize + 1) / 2); | 844 favicon_bounds_.set_y(lb.y() + (lb.height() - gfx::kFaviconSize + 1) / 2); |
788 MaybeAdjustLeftForPinnedTab(&favicon_bounds_); | 845 MaybeAdjustLeftForPinnedTab(&favicon_bounds_); |
789 } | 846 } |
847 if (throbber_) | |
848 throbber_->SetBoundsRect(favicon_bounds_); | |
790 | 849 |
791 showing_close_button_ = ShouldShowCloseBox(); | 850 showing_close_button_ = ShouldShowCloseBox(); |
792 if (showing_close_button_) { | 851 if (showing_close_button_) { |
793 // If the ratio of the close button size to tab width exceeds the maximum. | 852 // If the ratio of the close button size to tab width exceeds the maximum. |
794 // The close button should be as large as possible so that there is a larger | 853 // The close button should be as large as possible so that there is a larger |
795 // hit-target for touch events. So the close button bounds extends to the | 854 // hit-target for touch events. So the close button bounds extends to the |
796 // edges of the tab. However, the larger hit-target should be active only | 855 // edges of the tab. However, the larger hit-target should be active only |
797 // for mouse events, and the close-image should show up in the right place. | 856 // for mouse events, and the close-image should show up in the right place. |
798 // So a border is added to the button with necessary padding. The close | 857 // So a border is added to the button with necessary padding. The close |
799 // button (BaseTab::TabCloseButton) makes sure the padding is a hit-target | 858 // button (BaseTab::TabCloseButton) makes sure the padding is a hit-target |
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1340 } | 1399 } |
1341 | 1400 |
1342 void Tab::PaintIcon(gfx::Canvas* canvas) { | 1401 void Tab::PaintIcon(gfx::Canvas* canvas) { |
1343 gfx::Rect bounds = favicon_bounds_; | 1402 gfx::Rect bounds = favicon_bounds_; |
1344 if (bounds.IsEmpty()) | 1403 if (bounds.IsEmpty()) |
1345 return; | 1404 return; |
1346 | 1405 |
1347 bounds.set_x(GetMirroredXForRect(bounds)); | 1406 bounds.set_x(GetMirroredXForRect(bounds)); |
1348 | 1407 |
1349 if (data().network_state != TabRendererData::NETWORK_STATE_NONE) { | 1408 if (data().network_state != TabRendererData::NETWORK_STATE_NONE) { |
1350 // Paint network activity (aka throbber) animation frame. | 1409 // Throbber will do its own painting. |
1351 ui::ThemeProvider* tp = GetThemeProvider(); | |
1352 if (data().network_state == TabRendererData::NETWORK_STATE_WAITING) { | |
1353 if (waiting_start_time_ == base::TimeTicks()) | |
1354 waiting_start_time_ = base::TimeTicks::Now(); | |
1355 | |
1356 waiting_state_.elapsed_time = | |
1357 base::TimeTicks::Now() - waiting_start_time_; | |
1358 gfx::PaintThrobberWaiting( | |
1359 canvas, bounds, tp->GetColor(ThemeProperties::COLOR_THROBBER_WAITING), | |
1360 waiting_state_.elapsed_time); | |
1361 } else { | |
1362 if (loading_start_time_ == base::TimeTicks()) | |
1363 loading_start_time_ = base::TimeTicks::Now(); | |
1364 | |
1365 waiting_state_.color = | |
1366 tp->GetColor(ThemeProperties::COLOR_THROBBER_WAITING); | |
1367 gfx::PaintThrobberSpinningAfterWaiting( | |
1368 canvas, bounds, | |
1369 tp->GetColor(ThemeProperties::COLOR_THROBBER_SPINNING), | |
1370 base::TimeTicks::Now() - loading_start_time_, &waiting_state_); | |
1371 } | |
1372 } else if (should_display_crashed_favicon_) { | 1410 } else if (should_display_crashed_favicon_) { |
1373 // Paint crash favicon. | 1411 // Paint crash favicon. |
1374 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 1412 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
1375 gfx::ImageSkia crashed_favicon(*rb.GetImageSkiaNamed(IDR_SAD_FAVICON)); | 1413 gfx::ImageSkia crashed_favicon(*rb.GetImageSkiaNamed(IDR_SAD_FAVICON)); |
1376 bounds.set_y(bounds.y() + favicon_hiding_offset_); | 1414 bounds.set_y(bounds.y() + favicon_hiding_offset_); |
1377 DrawIconCenter(canvas, crashed_favicon, 0, | 1415 DrawIconCenter(canvas, crashed_favicon, 0, |
1378 crashed_favicon.width(), | 1416 crashed_favicon.width(), |
1379 crashed_favicon.height(), | 1417 crashed_favicon.height(), |
1380 bounds, true, SkPaint()); | 1418 bounds, true, SkPaint()); |
1381 } else if (!data().favicon.isNull()) { | 1419 } else if (!data().favicon.isNull()) { |
1382 // Paint the normal favicon. | 1420 // Paint the normal favicon. |
1383 DrawIconCenter(canvas, data().favicon, 0, | 1421 DrawIconCenter(canvas, data().favicon, 0, |
1384 data().favicon.width(), | 1422 data().favicon.width(), |
1385 data().favicon.height(), | 1423 data().favicon.height(), |
1386 bounds, true, SkPaint()); | 1424 bounds, true, SkPaint()); |
1387 } | 1425 } |
1388 } | 1426 } |
1389 | 1427 |
1390 void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, | 1428 void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState state) { |
1391 TabRendererData::NetworkState state) { | 1429 if (controller_->IsImmersiveStyle()) { |
1392 if (state == TabRendererData::NETWORK_STATE_WAITING) { | 1430 if (state == TabRendererData::NETWORK_STATE_WAITING) { |
1393 // Waiting steps backwards. | 1431 // Waiting steps backwards. |
1394 immersive_loading_step_ = | 1432 immersive_loading_step_ = |
1395 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % | 1433 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % |
1396 kImmersiveLoadingStepCount; | 1434 kImmersiveLoadingStepCount; |
1397 } else if (state == TabRendererData::NETWORK_STATE_LOADING) { | 1435 } else if (state == TabRendererData::NETWORK_STATE_LOADING) { |
1398 immersive_loading_step_ = (immersive_loading_step_ + 1) % | 1436 immersive_loading_step_ = (immersive_loading_step_ + 1) % |
1399 kImmersiveLoadingStepCount; | 1437 kImmersiveLoadingStepCount; |
1400 } else { | 1438 } else { |
1401 waiting_start_time_ = base::TimeTicks(); | 1439 immersive_loading_step_ = 0; |
1402 loading_start_time_ = base::TimeTicks(); | 1440 } |
1403 waiting_state_ = gfx::ThrobberWaitingState(); | 1441 |
1404 immersive_loading_step_ = 0; | 1442 SchedulePaintInRect(GetImmersiveBarRect()); |
1443 return; | |
1405 } | 1444 } |
1406 if (controller_->IsImmersiveStyle()) { | 1445 |
1407 SchedulePaintInRect(GetImmersiveBarRect()); | 1446 const bool needs_throbber = state != TabRendererData::NETWORK_STATE_NONE; |
1408 } else { | 1447 if (needs_throbber && !throbber_) { |
1448 throbber_ = new ThrobberView(this, favicon_bounds_); | |
1449 ScheduleIconPaint(); // Repaint the icon area to not show the icon. | |
1450 } else if (!needs_throbber) { | |
1451 delete throbber_; | |
sky
2015/10/08 15:52:23
I would hide the throbber when you don't need it r
tapted
2015/10/09 06:39:02
Done.
| |
1452 throbber_ = nullptr; | |
1409 ScheduleIconPaint(); | 1453 ScheduleIconPaint(); |
1410 } | 1454 } |
1455 if (throbber_) | |
1456 throbber_->SchedulePaint(); | |
1411 } | 1457 } |
1412 | 1458 |
1413 int Tab::IconCapacity() const { | 1459 int Tab::IconCapacity() const { |
1414 const gfx::Size min_size(GetMinimumUnselectedSize()); | 1460 const gfx::Size min_size(GetMinimumUnselectedSize()); |
1415 if (height() < min_size.height()) | 1461 if (height() < min_size.height()) |
1416 return 0; | 1462 return 0; |
1417 const int available_width = std::max(0, width() - min_size.width()); | 1463 const int available_width = std::max(0, width() - min_size.width()); |
1418 // All icons are the same size as the favicon. | 1464 // All icons are the same size as the favicon. |
1419 const int icon_width = gfx::kFaviconSize; | 1465 const int icon_width = gfx::kFaviconSize; |
1420 // We need enough space to display the icons flush against each other. | 1466 // We need enough space to display the icons flush against each other. |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1679 const gfx::ImageSkia& image) { | 1725 const gfx::ImageSkia& image) { |
1680 DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE); | 1726 DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE); |
1681 ImageCacheEntry entry; | 1727 ImageCacheEntry entry; |
1682 entry.resource_id = resource_id; | 1728 entry.resource_id = resource_id; |
1683 entry.scale_factor = scale_factor; | 1729 entry.scale_factor = scale_factor; |
1684 entry.image = image; | 1730 entry.image = image; |
1685 image_cache_->push_front(entry); | 1731 image_cache_->push_front(entry); |
1686 if (image_cache_->size() > kMaxImageCacheSize) | 1732 if (image_cache_->size() > kMaxImageCacheSize) |
1687 image_cache_->pop_back(); | 1733 image_cache_->pop_back(); |
1688 } | 1734 } |
OLD | NEW |