| 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 |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/debug/alias.h" | 12 #include "base/debug/alias.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/metrics/user_metrics.h" | 14 #include "base/metrics/user_metrics.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 16 #include "build/build_config.h" | 16 #include "build/build_config.h" |
| 17 #include "cc/paint/paint_shader.h" | 17 #include "cc/paint/paint_flags.h" |
| 18 #include "cc/paint/paint_recorder.h" |
| 18 #include "chrome/app/vector_icons/vector_icons.h" | 19 #include "chrome/app/vector_icons/vector_icons.h" |
| 19 #include "chrome/browser/themes/theme_properties.h" | 20 #include "chrome/browser/themes/theme_properties.h" |
| 20 #include "chrome/browser/ui/browser.h" | 21 #include "chrome/browser/ui/browser.h" |
| 21 #include "chrome/browser/ui/layout_constants.h" | 22 #include "chrome/browser/ui/layout_constants.h" |
| 22 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" | 23 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" |
| 23 #include "chrome/browser/ui/tabs/tab_utils.h" | 24 #include "chrome/browser/ui/tabs/tab_utils.h" |
| 24 #include "chrome/browser/ui/view_ids.h" | 25 #include "chrome/browser/ui/view_ids.h" |
| 25 #include "chrome/browser/ui/views/frame/browser_view.h" | 26 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 26 #include "chrome/browser/ui/views/tabs/alert_indicator_button.h" | 27 #include "chrome/browser/ui/views/tabs/alert_indicator_button.h" |
| 27 #include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" | 28 #include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 | 87 |
| 87 // How opaque to make the hover state (out of 1). | 88 // How opaque to make the hover state (out of 1). |
| 88 const double kHoverOpacity = 0.33; | 89 const double kHoverOpacity = 0.33; |
| 89 | 90 |
| 90 // Opacity of the active tab background painted over inactive selected tabs. | 91 // Opacity of the active tab background painted over inactive selected tabs. |
| 91 const double kSelectedTabOpacity = 0.3; | 92 const double kSelectedTabOpacity = 0.3; |
| 92 | 93 |
| 93 // Inactive selected tabs have their throb value scaled by this. | 94 // Inactive selected tabs have their throb value scaled by this. |
| 94 const double kSelectedTabThrobScale = 0.95 - kSelectedTabOpacity; | 95 const double kSelectedTabThrobScale = 0.95 - kSelectedTabOpacity; |
| 95 | 96 |
| 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. | |
| 98 // 8 = normal/incognito, active/inactive, 2 sizes within tabstrip. | |
| 99 const size_t kMaxImageCacheSize = 8; | |
| 100 | |
| 101 const char kTabCloseButtonName[] = "TabCloseButton"; | 97 const char kTabCloseButtonName[] = "TabCloseButton"; |
| 102 | 98 |
| 103 //////////////////////////////////////////////////////////////////////////////// | 99 //////////////////////////////////////////////////////////////////////////////// |
| 104 // ImageCacheEntryMetadata | |
| 105 // | |
| 106 // All metadata necessary to uniquely identify a cached image. | |
| 107 struct ImageCacheEntryMetadata { | |
| 108 ImageCacheEntryMetadata(SkColor fill_color, | |
| 109 SkColor stroke_color, | |
| 110 bool use_fill_and_stroke_images, | |
| 111 float scale_factor, | |
| 112 const gfx::Size& size); | |
| 113 | |
| 114 ~ImageCacheEntryMetadata(); | |
| 115 | |
| 116 bool operator==(const ImageCacheEntryMetadata& rhs) const; | |
| 117 | |
| 118 SkColor fill_color; | |
| 119 SkColor stroke_color; | |
| 120 bool use_fill_and_stroke_images; | |
| 121 float scale_factor; | |
| 122 gfx::Size size; | |
| 123 }; | |
| 124 | |
| 125 ImageCacheEntryMetadata::ImageCacheEntryMetadata( | |
| 126 SkColor fill_color, | |
| 127 SkColor stroke_color, | |
| 128 bool use_fill_and_stroke_images, | |
| 129 float scale_factor, | |
| 130 const gfx::Size& size) | |
| 131 : fill_color(fill_color), | |
| 132 stroke_color(stroke_color), | |
| 133 use_fill_and_stroke_images(use_fill_and_stroke_images), | |
| 134 scale_factor(scale_factor), | |
| 135 size(size) {} | |
| 136 | |
| 137 ImageCacheEntryMetadata::~ImageCacheEntryMetadata() {} | |
| 138 | |
| 139 bool ImageCacheEntryMetadata::operator==( | |
| 140 const ImageCacheEntryMetadata& rhs) const { | |
| 141 return fill_color == rhs.fill_color && stroke_color == rhs.stroke_color && | |
| 142 use_fill_and_stroke_images == rhs.use_fill_and_stroke_images && | |
| 143 scale_factor == rhs.scale_factor && size == rhs.size; | |
| 144 } | |
| 145 | |
| 146 //////////////////////////////////////////////////////////////////////////////// | |
| 147 // ImageCacheEntry and cache management | |
| 148 // | |
| 149 // A cached image and the metadata used to generate it. | |
| 150 struct ImageCacheEntry { | |
| 151 ImageCacheEntry(const ImageCacheEntryMetadata& metadata, | |
| 152 const gfx::ImageSkia& fill_image, | |
| 153 const gfx::ImageSkia& stroke_image); | |
| 154 ~ImageCacheEntry(); | |
| 155 | |
| 156 ImageCacheEntryMetadata metadata; | |
| 157 gfx::ImageSkia fill_image; | |
| 158 gfx::ImageSkia stroke_image; | |
| 159 }; | |
| 160 | |
| 161 ImageCacheEntry::ImageCacheEntry(const ImageCacheEntryMetadata& metadata, | |
| 162 const gfx::ImageSkia& fill_image, | |
| 163 const gfx::ImageSkia& stroke_image) | |
| 164 : metadata(metadata), fill_image(fill_image), stroke_image(stroke_image) {} | |
| 165 | |
| 166 ImageCacheEntry::~ImageCacheEntry() {} | |
| 167 | |
| 168 typedef std::list<ImageCacheEntry> ImageCache; | |
| 169 | |
| 170 // As the majority of the tabs are inactive, and painting tabs is slowish, | |
| 171 // we cache a handful of the inactive tab backgrounds here. | |
| 172 static ImageCache* g_image_cache = nullptr; | |
| 173 | |
| 174 // Performs a one-time initialization of static resources such as tab images. | |
| 175 void InitTabResources() { | |
| 176 static bool initialized = false; | |
| 177 if (initialized) | |
| 178 return; | |
| 179 | |
| 180 initialized = true; | |
| 181 g_image_cache = new ImageCache(); | |
| 182 } | |
| 183 | |
| 184 //////////////////////////////////////////////////////////////////////////////// | |
| 185 // Drawing and utility functions | 100 // Drawing and utility functions |
| 186 | 101 |
| 187 // Returns the width of the tab endcap at scale 1. More precisely, this is the | 102 // Returns the width of the tab endcap at scale 1. More precisely, this is the |
| 188 // width of the curve making up either the outer or inner edge of the stroke; | 103 // width of the curve making up either the outer or inner edge of the stroke; |
| 189 // since these two curves are horizontally offset by 1 px (regardless of scale), | 104 // since these two curves are horizontally offset by 1 px (regardless of scale), |
| 190 // the total width of the endcap from tab outer edge to the inside end of the | 105 // the total width of the endcap from tab outer edge to the inside end of the |
| 191 // stroke inner edge is (GetUnscaledEndcapWidth() * scale) + 1. | 106 // stroke inner edge is (GetUnscaledEndcapWidth() * scale) + 1. |
| 192 float GetUnscaledEndcapWidth() { | 107 float GetUnscaledEndcapWidth() { |
| 193 return GetLayoutInsets(TAB).left() - 0.5f; | 108 return GetLayoutInsets(TAB).left() - 0.5f; |
| 194 } | 109 } |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 alert_indicator_button_(nullptr), | 442 alert_indicator_button_(nullptr), |
| 528 close_button_(nullptr), | 443 close_button_(nullptr), |
| 529 title_(new views::Label()), | 444 title_(new views::Label()), |
| 530 tab_activated_with_last_tap_down_(false), | 445 tab_activated_with_last_tap_down_(false), |
| 531 hover_controller_(this), | 446 hover_controller_(this), |
| 532 showing_icon_(false), | 447 showing_icon_(false), |
| 533 showing_alert_indicator_(false), | 448 showing_alert_indicator_(false), |
| 534 showing_close_button_(false), | 449 showing_close_button_(false), |
| 535 button_color_(SK_ColorTRANSPARENT) { | 450 button_color_(SK_ColorTRANSPARENT) { |
| 536 DCHECK(controller); | 451 DCHECK(controller); |
| 537 InitTabResources(); | |
| 538 | 452 |
| 539 // So we get don't get enter/exit on children and don't prematurely stop the | 453 // So we get don't get enter/exit on children and don't prematurely stop the |
| 540 // hover. | 454 // hover. |
| 541 set_notify_enter_exit_on_child(true); | 455 set_notify_enter_exit_on_child(true); |
| 542 | 456 |
| 543 set_id(VIEW_ID_TAB); | 457 set_id(VIEW_ID_TAB); |
| 544 | 458 |
| 545 SetBorder(views::CreateEmptyBorder(GetLayoutInsets(TAB))); | 459 SetBorder(views::CreateEmptyBorder(GetLayoutInsets(TAB))); |
| 546 | 460 |
| 547 title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD); | 461 title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD); |
| (...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1111 if (data().blocked == old.blocked) | 1025 if (data().blocked == old.blocked) |
| 1112 return; | 1026 return; |
| 1113 | 1027 |
| 1114 if (data().blocked) | 1028 if (data().blocked) |
| 1115 StartPulse(); | 1029 StartPulse(); |
| 1116 else | 1030 else |
| 1117 StopPulse(); | 1031 StopPulse(); |
| 1118 } | 1032 } |
| 1119 | 1033 |
| 1120 void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) { | 1034 void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) { |
| 1121 const int kActiveTabFillId = | 1035 int active_tab_fill_id = 0; |
| 1122 GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR) ? IDR_THEME_TOOLBAR | 1036 int active_tab_y_offset = 0; |
| 1123 : 0; | 1037 if (GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR)) { |
| 1124 const int y_offset = -GetLayoutInsets(TAB).top(); | 1038 active_tab_fill_id = IDR_THEME_TOOLBAR; |
| 1039 active_tab_y_offset = -GetLayoutInsets(TAB).top(); |
| 1040 } |
| 1041 |
| 1125 if (IsActive()) { | 1042 if (IsActive()) { |
| 1126 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, | 1043 PaintTabBackground(canvas, true /* active */, active_tab_fill_id, |
| 1127 y_offset); | 1044 active_tab_y_offset, nullptr /* clip */); |
| 1128 } else { | 1045 } else { |
| 1129 PaintInactiveTabBackground(canvas, clip); | 1046 PaintInactiveTabBackground(canvas, clip); |
| 1130 | 1047 |
| 1131 const double throb_value = GetThrobValue(); | 1048 const double throb_value = GetThrobValue(); |
| 1132 if (throb_value > 0) { | 1049 if (throb_value > 0) { |
| 1133 canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), | 1050 canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), |
| 1134 GetLocalBounds()); | 1051 GetLocalBounds()); |
| 1135 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, | 1052 PaintTabBackground(canvas, true /* active */, active_tab_fill_id, |
| 1136 y_offset); | 1053 active_tab_y_offset, nullptr /* clip */); |
| 1137 canvas->Restore(); | 1054 canvas->Restore(); |
| 1138 } | 1055 } |
| 1139 } | 1056 } |
| 1140 | 1057 |
| 1141 if (showing_icon_) | 1058 if (showing_icon_) |
| 1142 PaintIcon(canvas); | 1059 PaintIcon(canvas); |
| 1143 } | 1060 } |
| 1144 | 1061 |
| 1145 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, | 1062 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, |
| 1146 const gfx::Path& clip) { | 1063 const gfx::Path& clip) { |
| 1147 bool has_custom_image; | 1064 bool has_custom_image; |
| 1148 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); | 1065 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); |
| 1066 |
| 1067 // The offset used to read from the image specified by |fill_id|. |
| 1068 int y_offset = 0; |
| 1069 |
| 1070 if (!has_custom_image) { |
| 1071 fill_id = 0; |
| 1072 } else if (!GetThemeProvider()->HasCustomImage(fill_id)) { |
| 1073 // If there's a custom frame image but no custom image for the tab itself, |
| 1074 // then the tab's background will be the frame's image, so we need to |
| 1075 // provide an offset into the image to read from. |
| 1076 y_offset = background_offset_.y(); |
| 1077 } |
| 1078 |
| 1079 PaintTabBackground(canvas, false /* active */, fill_id, y_offset, |
| 1080 controller_->MaySetClip() ? &clip : nullptr); |
| 1081 } |
| 1082 |
| 1083 void Tab::PaintTabBackground(gfx::Canvas* canvas, |
| 1084 bool active, |
| 1085 int fill_id, |
| 1086 int y_offset, |
| 1087 const gfx::Path* clip) { |
| 1088 // |y_offset| is only set when |fill_id| is being used. |
| 1089 DCHECK(!y_offset || fill_id); |
| 1090 |
| 1149 const ui::ThemeProvider* tp = GetThemeProvider(); | 1091 const ui::ThemeProvider* tp = GetThemeProvider(); |
| 1092 const SkColor active_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR); |
| 1093 const SkColor inactive_color = |
| 1094 tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB); |
| 1095 const SkColor stroke_color = controller_->GetToolbarTopSeparatorColor(); |
| 1096 const bool paint_hover_effect = !active && hover_controller_.ShouldDraw(); |
| 1150 | 1097 |
| 1151 // We only cache the image when it's the default image and we're not hovered, | 1098 // If there is a |fill_id| we don't try to cache. This could be improved |
| 1152 // to avoid caching a background image that isn't the same for all tabs. | 1099 // but would require knowing then the image from the ThemeProvider had been |
| 1153 if (has_custom_image) { | 1100 // changed, and invalidating when the tab's x-coordinate or background_offset_ |
| 1154 // If the theme is providing a custom background image, then its top edge | 1101 // changed. |
| 1155 // should be at the top of the tab. Otherwise, we assume that the background | 1102 // Similarly, if |paint_hover_effect|, we don't try to cache since hover |
| 1156 // image is a composited foreground + frame image. Note that if the theme | 1103 // effects change on every invalidation and we would need to invalidate the |
| 1157 // is only providing a custom frame image, |has_custom_image| will be true, | 1104 // cache based on the hover states. |
| 1158 // but we should use the |background_offset_| here. | 1105 if (fill_id || paint_hover_effect) { |
| 1159 const int y_offset = | 1106 gfx::Path fill_path = GetFillPath(canvas->image_scale(), size()); |
| 1160 tp->HasCustomImage(fill_id) ? 0 : background_offset_.y(); | 1107 gfx::Path stroke_path = |
| 1161 PaintTabBackgroundUsingFillId(canvas, canvas, false, fill_id, y_offset); | 1108 GetBorderPath(canvas->image_scale(), false, false, size()); |
| 1162 return; | 1109 PaintTabBackgroundFill(canvas, fill_path, active, paint_hover_effect, |
| 1163 } | 1110 active_color, inactive_color, fill_id, y_offset); |
| 1164 if (hover_controller_.ShouldDraw()) { | 1111 gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr); |
| 1165 PaintTabBackgroundUsingFillId(canvas, canvas, false, 0, 0); | 1112 if (clip) |
| 1113 canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true); |
| 1114 PaintTabBackgroundStroke(canvas, fill_path, stroke_path, active, |
| 1115 stroke_color); |
| 1166 return; | 1116 return; |
| 1167 } | 1117 } |
| 1168 | 1118 |
| 1169 // For efficiency, we don't use separate fill and stroke images unless we | 1119 BackgroundCache& cache = |
| 1170 // really need to clip the stroke and not the fill (for stacked tabs). This | 1120 active ? background_active_cache_ : background_inactive_cache_; |
| 1171 // saves memory and avoids an extra image draw at the cost of recalculating | 1121 if (!cache.CacheKeyMatches(canvas->image_scale(), size(), active_color, |
| 1172 // the images when MaySetClip() toggles. | 1122 inactive_color, stroke_color)) { |
| 1173 const bool use_fill_and_stroke_images = controller_->MaySetClip(); | 1123 gfx::Path fill_path = GetFillPath(canvas->image_scale(), size()); |
| 1124 gfx::Path stroke_path = |
| 1125 GetBorderPath(canvas->image_scale(), false, false, size()); |
| 1126 cc::PaintRecorder recorder; |
| 1174 | 1127 |
| 1175 const ImageCacheEntryMetadata metadata( | 1128 { |
| 1176 tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), | 1129 gfx::Canvas cache_canvas( |
| 1177 controller_->GetToolbarTopSeparatorColor(), use_fill_and_stroke_images, | 1130 recorder.beginRecording(size().width(), size().height()), |
| 1178 canvas->image_scale(), size()); | 1131 canvas->image_scale()); |
| 1179 auto it = std::find_if( | 1132 PaintTabBackgroundFill(&cache_canvas, fill_path, active, |
| 1180 g_image_cache->begin(), g_image_cache->end(), | 1133 paint_hover_effect, active_color, inactive_color, |
| 1181 [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; }); | 1134 fill_id, y_offset); |
| 1182 if (it == g_image_cache->end()) { | 1135 cache.fill_record = recorder.finishRecordingAsPicture(); |
| 1183 gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false); | |
| 1184 if (use_fill_and_stroke_images) { | |
| 1185 gfx::Canvas tmp_fill_canvas(size(), canvas->image_scale(), false); | |
| 1186 PaintTabBackgroundUsingFillId(&tmp_fill_canvas, &tmp_canvas, false, 0, 0); | |
| 1187 g_image_cache->emplace_front( | |
| 1188 metadata, gfx::ImageSkia(tmp_fill_canvas.ExtractImageRep()), | |
| 1189 gfx::ImageSkia(tmp_canvas.ExtractImageRep())); | |
| 1190 } else { | |
| 1191 PaintTabBackgroundUsingFillId(&tmp_canvas, &tmp_canvas, false, 0, 0); | |
| 1192 g_image_cache->emplace_front( | |
| 1193 metadata, gfx::ImageSkia(), | |
| 1194 gfx::ImageSkia(tmp_canvas.ExtractImageRep())); | |
| 1195 } | 1136 } |
| 1196 if (g_image_cache->size() > kMaxImageCacheSize) | 1137 { |
| 1197 g_image_cache->pop_back(); | 1138 gfx::Canvas cache_canvas( |
| 1198 it = g_image_cache->begin(); | 1139 recorder.beginRecording(size().width(), size().height()), |
| 1140 canvas->image_scale()); |
| 1141 PaintTabBackgroundStroke(&cache_canvas, fill_path, stroke_path, active, |
| 1142 stroke_color); |
| 1143 cache.stroke_record = recorder.finishRecordingAsPicture(); |
| 1144 } |
| 1145 |
| 1146 cache.SetCacheKey(canvas->image_scale(), size(), active_color, |
| 1147 inactive_color, stroke_color); |
| 1199 } | 1148 } |
| 1200 | 1149 |
| 1201 gfx::ScopedCanvas scoped_canvas( | 1150 canvas->sk_canvas()->PlaybackPaintRecord(cache.fill_record); |
| 1202 use_fill_and_stroke_images ? canvas : nullptr); | 1151 gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr); |
| 1203 if (use_fill_and_stroke_images) { | 1152 if (clip) |
| 1204 canvas->DrawImageInt(it->fill_image, 0, 0); | 1153 canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true); |
| 1205 canvas->sk_canvas()->clipPath(clip, SkClipOp::kDifference, true); | 1154 canvas->sk_canvas()->PlaybackPaintRecord(cache.stroke_record); |
| 1206 } | |
| 1207 canvas->DrawImageInt(it->stroke_image, 0, 0); | |
| 1208 } | 1155 } |
| 1209 | 1156 |
| 1210 void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas, | 1157 void Tab::PaintTabBackgroundFill(gfx::Canvas* canvas, |
| 1211 gfx::Canvas* stroke_canvas, | 1158 const gfx::Path& fill_path, |
| 1212 bool is_active, | 1159 bool active, |
| 1213 int fill_id, | 1160 bool paint_hover_effect, |
| 1214 int y_offset) { | 1161 SkColor active_color, |
| 1215 gfx::Path fill; | 1162 SkColor inactive_color, |
| 1163 int fill_id, |
| 1164 int y_offset) { |
| 1165 gfx::ScopedCanvas scoped_canvas(canvas); |
| 1166 const float scale = canvas->UndoDeviceScaleFactor(); |
| 1167 |
| 1168 canvas->ClipPath(fill_path, true); |
| 1169 if (fill_id) { |
| 1170 gfx::ScopedCanvas scale_scoper(canvas); |
| 1171 canvas->sk_canvas()->scale(scale, scale); |
| 1172 canvas->TileImageInt(*GetThemeProvider()->GetImageSkiaNamed(fill_id), |
| 1173 GetMirroredX() + background_offset_.x(), y_offset, 0, |
| 1174 0, width(), height()); |
| 1175 } else { |
| 1176 cc::PaintFlags flags; |
| 1177 flags.setAntiAlias(true); |
| 1178 flags.setColor(active ? active_color : inactive_color); |
| 1179 canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), flags); |
| 1180 } |
| 1181 |
| 1182 if (paint_hover_effect) { |
| 1183 SkPoint hover_location(gfx::PointToSkPoint(hover_controller_.location())); |
| 1184 hover_location.scale(SkFloatToScalar(scale)); |
| 1185 const SkScalar kMinHoverRadius = 16; |
| 1186 const SkScalar radius = |
| 1187 std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius); |
| 1188 DrawHighlight(canvas, hover_location, radius * scale, |
| 1189 SkColorSetA(active_color, hover_controller_.GetAlpha())); |
| 1190 } |
| 1191 } |
| 1192 |
| 1193 void Tab::PaintTabBackgroundStroke(gfx::Canvas* canvas, |
| 1194 const gfx::Path& fill_path, |
| 1195 const gfx::Path& stroke_path, |
| 1196 bool active, |
| 1197 SkColor color) { |
| 1198 gfx::ScopedCanvas scoped_canvas(canvas); |
| 1199 const float scale = canvas->UndoDeviceScaleFactor(); |
| 1200 |
| 1201 if (!active) { |
| 1202 // Clip out the bottom line; this will be drawn for us by |
| 1203 // TabStrip::PaintChildren(). |
| 1204 canvas->ClipRect(gfx::RectF(width() * scale, height() * scale - 1)); |
| 1205 } |
| 1216 cc::PaintFlags flags; | 1206 cc::PaintFlags flags; |
| 1217 flags.setAntiAlias(true); | 1207 flags.setAntiAlias(true); |
| 1218 | 1208 flags.setColor(color); |
| 1219 // Draw the fill. | 1209 SkPath path; |
| 1220 { | 1210 Op(stroke_path, fill_path, kDifference_SkPathOp, &path); |
| 1221 gfx::ScopedCanvas scoped_canvas(fill_canvas); | 1211 canvas->DrawPath(path, flags); |
| 1222 const float scale = fill_canvas->UndoDeviceScaleFactor(); | |
| 1223 const ui::ThemeProvider* tp = GetThemeProvider(); | |
| 1224 const SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR); | |
| 1225 | |
| 1226 fill = GetFillPath(scale, size()); | |
| 1227 { | |
| 1228 gfx::ScopedCanvas clip_scoper(fill_canvas); | |
| 1229 fill_canvas->ClipPath(fill, true); | |
| 1230 if (fill_id) { | |
| 1231 gfx::ScopedCanvas scale_scoper(fill_canvas); | |
| 1232 fill_canvas->sk_canvas()->scale(scale, scale); | |
| 1233 fill_canvas->TileImageInt(*tp->GetImageSkiaNamed(fill_id), | |
| 1234 GetMirroredX() + background_offset_.x(), | |
| 1235 y_offset, 0, 0, width(), height()); | |
| 1236 } else { | |
| 1237 flags.setColor( | |
| 1238 is_active ? toolbar_color | |
| 1239 : tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB)); | |
| 1240 fill_canvas->DrawRect( | |
| 1241 gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), flags); | |
| 1242 } | |
| 1243 | |
| 1244 if (!is_active && hover_controller_.ShouldDraw()) { | |
| 1245 SkPoint hover_location( | |
| 1246 gfx::PointToSkPoint(hover_controller_.location())); | |
| 1247 hover_location.scale(SkFloatToScalar(scale)); | |
| 1248 const SkScalar kMinHoverRadius = 16; | |
| 1249 const SkScalar radius = | |
| 1250 std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius); | |
| 1251 DrawHighlight(fill_canvas, hover_location, radius * scale, | |
| 1252 SkColorSetA(toolbar_color, hover_controller_.GetAlpha())); | |
| 1253 } | |
| 1254 } | |
| 1255 } | |
| 1256 | |
| 1257 // Draw the stroke. | |
| 1258 { | |
| 1259 gfx::ScopedCanvas scoped_canvas(stroke_canvas); | |
| 1260 const float scale = stroke_canvas->UndoDeviceScaleFactor(); | |
| 1261 | |
| 1262 gfx::Path stroke = GetBorderPath(scale, false, false, size()); | |
| 1263 Op(stroke, fill, kDifference_SkPathOp, &stroke); | |
| 1264 if (!is_active) { | |
| 1265 // Clip out the bottom line; this will be drawn for us by | |
| 1266 // TabStrip::PaintChildren(). | |
| 1267 stroke_canvas->ClipRect( | |
| 1268 gfx::RectF(width() * scale, height() * scale - 1)); | |
| 1269 } | |
| 1270 flags.setColor(controller_->GetToolbarTopSeparatorColor()); | |
| 1271 stroke_canvas->DrawPath(stroke, flags); | |
| 1272 } | |
| 1273 } | 1212 } |
| 1274 | 1213 |
| 1275 void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon( | 1214 void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon( |
| 1276 gfx::Canvas* canvas, | 1215 gfx::Canvas* canvas, |
| 1277 const gfx::Rect& favicon_draw_bounds) { | 1216 const gfx::Rect& favicon_draw_bounds) { |
| 1278 // The pinned tab title changed indicator consists of two parts: | 1217 // The pinned tab title changed indicator consists of two parts: |
| 1279 // . a clear (totally transparent) part over the bottom right (or left in rtl) | 1218 // . a clear (totally transparent) part over the bottom right (or left in rtl) |
| 1280 // of the favicon. This is done by drawing the favicon to a layer, then | 1219 // of the favicon. This is done by drawing the favicon to a layer, then |
| 1281 // drawing the clear part on top of the favicon. | 1220 // drawing the clear part on top of the favicon. |
| 1282 // . a circle in the bottom right (or left in rtl) of the favicon. | 1221 // . a circle in the bottom right (or left in rtl) of the favicon. |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1486 gfx::Rect bounds = favicon_bounds_; | 1425 gfx::Rect bounds = favicon_bounds_; |
| 1487 if (bounds.IsEmpty()) | 1426 if (bounds.IsEmpty()) |
| 1488 return; | 1427 return; |
| 1489 | 1428 |
| 1490 // Extends the area to the bottom when the crash animation is in progress. | 1429 // Extends the area to the bottom when the crash animation is in progress. |
| 1491 if (crash_icon_animation_->is_animating()) | 1430 if (crash_icon_animation_->is_animating()) |
| 1492 bounds.set_height(height() - bounds.y()); | 1431 bounds.set_height(height() - bounds.y()); |
| 1493 bounds.set_x(GetMirroredXForRect(bounds)); | 1432 bounds.set_x(GetMirroredXForRect(bounds)); |
| 1494 SchedulePaintInRect(bounds); | 1433 SchedulePaintInRect(bounds); |
| 1495 } | 1434 } |
| 1435 |
| 1436 Tab::BackgroundCache::BackgroundCache() = default; |
| 1437 Tab::BackgroundCache::~BackgroundCache() = default; |
| OLD | NEW |