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 <stddef.h> | 7 #include <stddef.h> |
8 #include <limits> | 8 #include <limits> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 const double kSelectedTabOpacity = 0.3; | 91 const double kSelectedTabOpacity = 0.3; |
92 | 92 |
93 // Inactive selected tabs have their throb value scaled by this. | 93 // Inactive selected tabs have their throb value scaled by this. |
94 const double kSelectedTabThrobScale = 0.95 - kSelectedTabOpacity; | 94 const double kSelectedTabThrobScale = 0.95 - kSelectedTabOpacity; |
95 | 95 |
96 // Max number of images to cache. This has to be at least two since rounding | 96 // Max number of images to cache. This has to be at least two since rounding |
97 // errors may lead to tabs in the same tabstrip having different sizes. | 97 // errors may lead to tabs in the same tabstrip having different sizes. |
98 // 8 = normal/incognito, active/inactive, 2 sizes within tabstrip. | 98 // 8 = normal/incognito, active/inactive, 2 sizes within tabstrip. |
99 const size_t kMaxImageCacheSize = 8; | 99 const size_t kMaxImageCacheSize = 8; |
100 | 100 |
101 // Height of the miniature tab strip in immersive mode. | |
102 const int kImmersiveTabHeight = 3; | |
103 | |
104 // Height of the small tab indicator rectangles in immersive mode. | |
105 const int kImmersiveBarHeight = 2; | |
106 | |
107 // Color for active and inactive tabs in the immersive mode light strip. These | |
108 // should be a little brighter than the color of the normal art assets for tabs, | |
109 // which for active tabs is 230, 230, 230 and for inactive is 184, 184, 184. | |
110 const SkColor kImmersiveActiveTabColor = SkColorSetRGB(235, 235, 235); | |
111 const SkColor kImmersiveInactiveTabColor = SkColorSetRGB(190, 190, 190); | |
112 | |
113 // The minimum opacity (out of 1) when a tab (either active or inactive) is | |
114 // throbbing in the immersive mode light strip. | |
115 const double kImmersiveTabMinThrobOpacity = 0.66; | |
116 | |
117 // Number of steps in the immersive mode loading animation. | |
118 const int kImmersiveLoadingStepCount = 32; | |
119 | |
120 const char kTabCloseButtonName[] = "TabCloseButton"; | 101 const char kTabCloseButtonName[] = "TabCloseButton"; |
121 | 102 |
122 //////////////////////////////////////////////////////////////////////////////// | 103 //////////////////////////////////////////////////////////////////////////////// |
123 // ImageCacheEntryMetadata | 104 // ImageCacheEntryMetadata |
124 // | 105 // |
125 // All metadata necessary to uniquely identify a cached image. | 106 // All metadata necessary to uniquely identify a cached image. |
126 struct ImageCacheEntryMetadata { | 107 struct ImageCacheEntryMetadata { |
127 ImageCacheEntryMetadata(SkColor fill_color, | 108 ImageCacheEntryMetadata(SkColor fill_color, |
128 SkColor stroke_color, | 109 SkColor stroke_color, |
129 bool use_fill_and_stroke_images, | 110 bool use_fill_and_stroke_images, |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 | 512 |
532 // static | 513 // static |
533 const char Tab::kViewClassName[] = "Tab"; | 514 const char Tab::kViewClassName[] = "Tab"; |
534 | 515 |
535 Tab::Tab(TabController* controller, gfx::AnimationContainer* container) | 516 Tab::Tab(TabController* controller, gfx::AnimationContainer* container) |
536 : controller_(controller), | 517 : controller_(controller), |
537 closing_(false), | 518 closing_(false), |
538 dragging_(false), | 519 dragging_(false), |
539 detached_(false), | 520 detached_(false), |
540 favicon_hiding_offset_(0), | 521 favicon_hiding_offset_(0), |
541 immersive_loading_step_(0), | |
542 should_display_crashed_favicon_(false), | 522 should_display_crashed_favicon_(false), |
543 pulse_animation_(new gfx::ThrobAnimation(this)), | 523 pulse_animation_(new gfx::ThrobAnimation(this)), |
544 crash_icon_animation_(new FaviconCrashAnimation(this)), | 524 crash_icon_animation_(new FaviconCrashAnimation(this)), |
545 animation_container_(container), | 525 animation_container_(container), |
546 throbber_(nullptr), | 526 throbber_(nullptr), |
547 alert_indicator_button_(nullptr), | 527 alert_indicator_button_(nullptr), |
548 close_button_(nullptr), | 528 close_button_(nullptr), |
549 title_(new views::Label()), | 529 title_(new views::Label()), |
550 tab_activated_with_last_tap_down_(false), | 530 tab_activated_with_last_tap_down_(false), |
551 hover_controller_(this), | 531 hover_controller_(this), |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 return kTouchWidth; | 720 return kTouchWidth; |
741 } | 721 } |
742 | 722 |
743 // static | 723 // static |
744 int Tab::GetPinnedWidth() { | 724 int Tab::GetPinnedWidth() { |
745 constexpr int kTabPinnedContentWidth = 23; | 725 constexpr int kTabPinnedContentWidth = 23; |
746 return GetMinimumInactiveSize().width() + kTabPinnedContentWidth; | 726 return GetMinimumInactiveSize().width() + kTabPinnedContentWidth; |
747 } | 727 } |
748 | 728 |
749 // static | 729 // static |
750 int Tab::GetImmersiveHeight() { | |
751 return kImmersiveTabHeight; | |
752 } | |
753 | |
754 // static | |
755 float Tab::GetInverseDiagonalSlope() { | 730 float Tab::GetInverseDiagonalSlope() { |
756 // This is computed from the border path as follows: | 731 // This is computed from the border path as follows: |
757 // * The unscaled endcap width is enough for the whole stroke outer curve, | 732 // * The unscaled endcap width is enough for the whole stroke outer curve, |
758 // i.e. the side diagonal plus the curves on both its ends. | 733 // i.e. the side diagonal plus the curves on both its ends. |
759 // * The bottom and top curve are each (2 * scale) px wide, so the diagonal is | 734 // * The bottom and top curve are each (2 * scale) px wide, so the diagonal is |
760 // (unscaled endcap width - 2 - 2) * scale px wide. | 735 // (unscaled endcap width - 2 - 2) * scale px wide. |
761 // * The bottom and top curve are each 1.5 px high. Additionally, there is an | 736 // * The bottom and top curve are each 1.5 px high. Additionally, there is an |
762 // extra 1 px below the bottom curve and (scale - 1) px above the top curve, | 737 // extra 1 px below the bottom curve and (scale - 1) px above the top curve, |
763 // so the diagonal is ((height - 1.5 - 1.5) * scale - 1 - (scale - 1)) px | 738 // so the diagonal is ((height - 1.5 - 1.5) * scale - 1 - (scale - 1)) px |
764 // high. | 739 // high. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
848 // only happen during animations). | 823 // only happen during animations). |
849 if (width() < GetMinimumInactiveSize().width() && !data().pinned) | 824 if (width() < GetMinimumInactiveSize().width() && !data().pinned) |
850 return; | 825 return; |
851 | 826 |
852 gfx::Path clip; | 827 gfx::Path clip; |
853 if (!controller_->ShouldPaintTab( | 828 if (!controller_->ShouldPaintTab( |
854 this, base::Bind(&GetBorderPath, canvas->image_scale(), true, false), | 829 this, base::Bind(&GetBorderPath, canvas->image_scale(), true, false), |
855 &clip)) | 830 &clip)) |
856 return; | 831 return; |
857 | 832 |
858 if (controller_->IsImmersiveStyle()) | 833 PaintTab(canvas, clip); |
859 PaintImmersiveTab(canvas); | |
860 else | |
861 PaintTab(canvas, clip); | |
862 } | 834 } |
863 | 835 |
864 void Tab::Layout() { | 836 void Tab::Layout() { |
865 const gfx::Rect lb = GetContentsBounds(); | 837 const gfx::Rect lb = GetContentsBounds(); |
866 showing_icon_ = ShouldShowIcon(); | 838 showing_icon_ = ShouldShowIcon(); |
867 // See comments in IconCapacity(). | 839 // See comments in IconCapacity(). |
868 const int extra_padding = | 840 const int extra_padding = |
869 (controller_->ShouldHideCloseButtonForInactiveTabs() || | 841 (controller_->ShouldHideCloseButtonForInactiveTabs() || |
870 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; | 842 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; |
871 const int start = lb.x() + extra_padding; | 843 const int start = lb.x() + extra_padding; |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1163 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, | 1135 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, |
1164 y_offset); | 1136 y_offset); |
1165 canvas->Restore(); | 1137 canvas->Restore(); |
1166 } | 1138 } |
1167 } | 1139 } |
1168 | 1140 |
1169 if (showing_icon_) | 1141 if (showing_icon_) |
1170 PaintIcon(canvas); | 1142 PaintIcon(canvas); |
1171 } | 1143 } |
1172 | 1144 |
1173 void Tab::PaintImmersiveTab(gfx::Canvas* canvas) { | |
1174 // Use transparency for the draw-attention animation. | |
1175 int alpha = 255; | |
1176 if (pulse_animation_->is_animating() && !data().pinned) { | |
1177 alpha = pulse_animation_->CurrentValueBetween( | |
1178 255, gfx::ToRoundedInt(255 * kImmersiveTabMinThrobOpacity)); | |
1179 } | |
1180 | |
1181 // Draw a gray rectangle to represent the tab. This works for pinned tabs as | |
1182 // well as regular ones. The active tab has a brigher bar. | |
1183 SkColor color = | |
1184 IsActive() ? kImmersiveActiveTabColor : kImmersiveInactiveTabColor; | |
1185 gfx::Rect bar_rect = GetImmersiveBarRect(); | |
1186 canvas->FillRect(bar_rect, SkColorSetA(color, alpha)); | |
1187 | |
1188 // Paint network activity indicator. | |
1189 // TODO(jamescook): Replace this placeholder animation with a real one. | |
1190 // For now, let's go with a Cylon eye effect, but in blue. | |
1191 if (data().network_state != TabRendererData::NETWORK_STATE_NONE && | |
1192 data().network_state != TabRendererData::NETWORK_STATE_ERROR) { | |
1193 const SkColor kEyeColor = SkColorSetARGB(alpha, 71, 138, 217); | |
1194 int eye_width = bar_rect.width() / 3; | |
1195 int eye_offset = bar_rect.width() * immersive_loading_step_ / | |
1196 kImmersiveLoadingStepCount; | |
1197 if (eye_offset + eye_width < bar_rect.width()) { | |
1198 // Draw a single indicator strip because it fits inside |bar_rect|. | |
1199 gfx::Rect eye_rect( | |
1200 bar_rect.x() + eye_offset, 0, eye_width, kImmersiveBarHeight); | |
1201 canvas->FillRect(eye_rect, kEyeColor); | |
1202 } else { | |
1203 // Draw two indicators to simulate the eye "wrapping around" to the left | |
1204 // side. The first part fills the remainder of the bar. | |
1205 int right_eye_width = bar_rect.width() - eye_offset; | |
1206 gfx::Rect right_eye_rect( | |
1207 bar_rect.x() + eye_offset, 0, right_eye_width, kImmersiveBarHeight); | |
1208 canvas->FillRect(right_eye_rect, kEyeColor); | |
1209 // The second part parts the remaining |eye_width| on the left. | |
1210 int left_eye_width = eye_offset + eye_width - bar_rect.width(); | |
1211 gfx::Rect left_eye_rect( | |
1212 bar_rect.x(), 0, left_eye_width, kImmersiveBarHeight); | |
1213 canvas->FillRect(left_eye_rect, kEyeColor); | |
1214 } | |
1215 } | |
1216 } | |
1217 | |
1218 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, | 1145 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, |
1219 const gfx::Path& clip) { | 1146 const gfx::Path& clip) { |
1220 bool has_custom_image; | 1147 bool has_custom_image; |
1221 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); | 1148 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); |
1222 const ui::ThemeProvider* tp = GetThemeProvider(); | 1149 const ui::ThemeProvider* tp = GetThemeProvider(); |
1223 | 1150 |
1224 // We only cache the image when it's the default image and we're not hovered, | 1151 // We only cache the image when it's the default image and we're not hovered, |
1225 // to avoid caching a background image that isn't the same for all tabs. | 1152 // to avoid caching a background image that isn't the same for all tabs. |
1226 if (has_custom_image) { | 1153 if (has_custom_image) { |
1227 // If the theme is providing a custom background image, then its top edge | 1154 // If the theme is providing a custom background image, then its top edge |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1422 PaintPinnedTabTitleChangedIndicatorAndIcon(canvas, bounds); | 1349 PaintPinnedTabTitleChangedIndicatorAndIcon(canvas, bounds); |
1423 } else if (!favicon_.isNull()) { | 1350 } else if (!favicon_.isNull()) { |
1424 canvas->DrawImageInt(favicon_, 0, 0, bounds.width(), bounds.height(), | 1351 canvas->DrawImageInt(favicon_, 0, 0, bounds.width(), bounds.height(), |
1425 bounds.x(), bounds.y(), bounds.width(), | 1352 bounds.x(), bounds.y(), bounds.width(), |
1426 bounds.height(), false); | 1353 bounds.height(), false); |
1427 } | 1354 } |
1428 } | 1355 } |
1429 | 1356 |
1430 void Tab::AdvanceLoadingAnimation() { | 1357 void Tab::AdvanceLoadingAnimation() { |
1431 const TabRendererData::NetworkState state = data().network_state; | 1358 const TabRendererData::NetworkState state = data().network_state; |
1432 if (controller_->IsImmersiveStyle()) { | |
1433 throbber_->SetVisible(false); | |
1434 if (state == TabRendererData::NETWORK_STATE_WAITING) { | |
1435 // Waiting steps backwards. | |
1436 immersive_loading_step_ = | |
1437 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % | |
1438 kImmersiveLoadingStepCount; | |
1439 } else if (state == TabRendererData::NETWORK_STATE_LOADING) { | |
1440 immersive_loading_step_ = | |
1441 (immersive_loading_step_ + 1) % kImmersiveLoadingStepCount; | |
1442 } else { | |
1443 immersive_loading_step_ = 0; | |
1444 } | |
1445 | |
1446 SchedulePaintInRect(GetImmersiveBarRect()); | |
1447 return; | |
1448 } | |
1449 | |
1450 if (state == TabRendererData::NETWORK_STATE_NONE || | 1359 if (state == TabRendererData::NETWORK_STATE_NONE || |
1451 state == TabRendererData::NETWORK_STATE_ERROR) { | 1360 state == TabRendererData::NETWORK_STATE_ERROR) { |
1452 throbber_->ResetStartTimes(); | 1361 throbber_->ResetStartTimes(); |
1453 throbber_->SetVisible(false); | 1362 throbber_->SetVisible(false); |
1454 ScheduleIconPaint(); | 1363 ScheduleIconPaint(); |
1455 return; | 1364 return; |
1456 } | 1365 } |
1457 | 1366 |
1458 // Since the throbber can animate for a long time, paint to a separate layer | 1367 // Since the throbber can animate for a long time, paint to a separate layer |
1459 // when possible to reduce repaint overhead. | 1368 // when possible to reduce repaint overhead. |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1577 gfx::Rect bounds = favicon_bounds_; | 1486 gfx::Rect bounds = favicon_bounds_; |
1578 if (bounds.IsEmpty()) | 1487 if (bounds.IsEmpty()) |
1579 return; | 1488 return; |
1580 | 1489 |
1581 // Extends the area to the bottom when the crash animation is in progress. | 1490 // Extends the area to the bottom when the crash animation is in progress. |
1582 if (crash_icon_animation_->is_animating()) | 1491 if (crash_icon_animation_->is_animating()) |
1583 bounds.set_height(height() - bounds.y()); | 1492 bounds.set_height(height() - bounds.y()); |
1584 bounds.set_x(GetMirroredXForRect(bounds)); | 1493 bounds.set_x(GetMirroredXForRect(bounds)); |
1585 SchedulePaintInRect(bounds); | 1494 SchedulePaintInRect(bounds); |
1586 } | 1495 } |
1587 | |
1588 gfx::Rect Tab::GetImmersiveBarRect() const { | |
1589 // The main bar is as wide as the normal tab's horizontal top line. | |
1590 gfx::Rect contents = GetContentsBounds(); | |
1591 contents.set_y(0); | |
1592 contents.set_height(kImmersiveBarHeight); | |
1593 return contents; | |
1594 } | |
OLD | NEW |