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

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

Issue 2803583003: ui: Remove use of bitmaps when painting tab backgrounds. (Closed)
Patch Set: tabbackground: with-cache Created 3 years, 8 months 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
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 <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
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 17 matching lines...) Expand all
212 bool ShouldThemifyFaviconForUrl(const GURL& url) { 127 bool ShouldThemifyFaviconForUrl(const GURL& url) {
213 return url.SchemeIs(content::kChromeUIScheme) && 128 return url.SchemeIs(content::kChromeUIScheme) &&
214 url.host() != chrome::kChromeUIHelpHost && 129 url.host() != chrome::kChromeUIHelpHost &&
215 url.host() != chrome::kChromeUIUberHost && 130 url.host() != chrome::kChromeUIUberHost &&
216 url.host() != chrome::kChromeUIAppLauncherPageHost; 131 url.host() != chrome::kChromeUIAppLauncherPageHost;
217 } 132 }
218 133
219 // Returns a path corresponding to the tab's content region inside the outer 134 // Returns a path corresponding to the tab's content region inside the outer
220 // stroke. 135 // stroke.
221 gfx::Path GetFillPath(float scale, const gfx::Size& size) { 136 gfx::Path GetFillPath(float scale, const gfx::Size& size) {
137 struct FillPathCache {
138 // The parameters used to build the path.
139 float scale;
140 gfx::Size size;
141
142 // The constructed path based on the parameters.
143 gfx::Path path;
144 };
145 // A cache sorted from most recently used to least.
146 static auto& cache = *new std::list<FillPathCache>;
147 static const int kCacheSize = 8;
148
149 // Find a match in the cache and move it to the front and return it.
150 for (auto it = cache.begin(); it != cache.end(); ++it) {
151 if (it->scale == scale && it->size == size) {
152 std::list<FillPathCache> hit;
153 hit.splice(hit.begin(), cache, it, std::next(it));
154 cache.splice(cache.begin(), std::move(hit));
155 return cache.front().path;
156 }
157 }
158
222 const float right = size.width() * scale; 159 const float right = size.width() * scale;
223 // The bottom of the tab needs to be pixel-aligned or else when we call 160 // The bottom of the tab needs to be pixel-aligned or else when we call
224 // ClipPath with anti-aliasing enabled it can cause artifacts. 161 // ClipPath with anti-aliasing enabled it can cause artifacts.
225 const float bottom = std::ceil(size.height() * scale); 162 const float bottom = std::ceil(size.height() * scale);
226 const float unscaled_endcap_width = GetUnscaledEndcapWidth(); 163 const float unscaled_endcap_width = GetUnscaledEndcapWidth();
227 164
228 gfx::Path fill; 165 gfx::Path fill;
229 fill.moveTo(right - 1, bottom); 166 fill.moveTo(right - 1, bottom);
230 fill.rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale, 167 fill.rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale,
231 -1.5 * scale); 168 -1.5 * scale);
232 fill.lineTo(right - 1 - (unscaled_endcap_width - 2) * scale, 2.5 * scale); 169 fill.lineTo(right - 1 - (unscaled_endcap_width - 2) * scale, 2.5 * scale);
233 // Prevent overdraw in the center near minimum width (only happens if 170 // Prevent overdraw in the center near minimum width (only happens if
234 // scale < 2). We could instead avoid this by increasing the tab inset 171 // scale < 2). We could instead avoid this by increasing the tab inset
235 // values, but that would shift all the content inward as well, unless we 172 // values, but that would shift all the content inward as well, unless we
236 // then overlapped the content on the endcaps, by which point we'd have a 173 // then overlapped the content on the endcaps, by which point we'd have a
237 // huge mess. 174 // huge mess.
238 const float scaled_endcap_width = 1 + unscaled_endcap_width * scale; 175 const float scaled_endcap_width = 1 + unscaled_endcap_width * scale;
239 const float overlap = scaled_endcap_width * 2 - right; 176 const float overlap = scaled_endcap_width * 2 - right;
240 const float offset = (overlap > 0) ? (overlap / 2) : 0; 177 const float offset = (overlap > 0) ? (overlap / 2) : 0;
241 fill.rCubicTo(-0.375 * scale, -1 * scale, -1.25 * scale + offset, 178 fill.rCubicTo(-0.375 * scale, -1 * scale, -1.25 * scale + offset,
242 -1.5 * scale, -2 * scale + offset, -1.5 * scale); 179 -1.5 * scale, -2 * scale + offset, -1.5 * scale);
243 if (overlap < 0) 180 if (overlap < 0)
244 fill.lineTo(scaled_endcap_width, scale); 181 fill.lineTo(scaled_endcap_width, scale);
245 fill.rCubicTo(-0.75 * scale, 0, -1.625 * scale - offset, 0.5 * scale, 182 fill.rCubicTo(-0.75 * scale, 0, -1.625 * scale - offset, 0.5 * scale,
246 -2 * scale - offset, 1.5 * scale); 183 -2 * scale - offset, 1.5 * scale);
247 fill.lineTo(1 + 2 * scale, bottom - 1.5 * scale); 184 fill.lineTo(1 + 2 * scale, bottom - 1.5 * scale);
248 fill.rCubicTo(-0.375 * scale, scale, -1.25 * scale, 1.5 * scale, -2 * scale, 185 fill.rCubicTo(-0.375 * scale, scale, -1.25 * scale, 1.5 * scale, -2 * scale,
249 1.5 * scale); 186 1.5 * scale);
250 fill.close(); 187 fill.close();
188
189 // If the cache is max size we need to drop the least recently used from the
190 // cache. Then add the new path to the front of the cache.
191 if (cache.size() >= kCacheSize)
192 cache.pop_back();
193 cache.emplace_front();
194 cache.front().scale = scale;
195 cache.front().size = size;
196 cache.front().path = fill;
197
251 return fill; 198 return fill;
252 } 199 }
253 200
254 // Returns a path corresponding to the tab's outer border for a given tab |size| 201 // Returns a path corresponding to the tab's outer border for a given tab |size|
255 // and |scale|. If |unscale_at_end| is true, this path will be normalized to a 202 // and |scale|. If |unscale_at_end| is true, this path will be normalized to a
256 // 1x scale by scaling by 1/scale before returning. If |extend_to_top| is true, 203 // 1x scale by scaling by 1/scale before returning. If |extend_to_top| is true,
257 // the path is extended vertically to the top of the tab bounds. The caller 204 // the path is extended vertically to the top of the tab bounds. The caller
258 // uses this for Fitts' Law purposes in maximized/fullscreen mode. 205 // uses this for Fitts' Law purposes in maximized/fullscreen mode.
259 gfx::Path GetBorderPath(float scale, 206 gfx::Path GetBorderPath(float scale,
260 bool unscale_at_end, 207 bool unscale_at_end,
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 alert_indicator_button_(nullptr), 474 alert_indicator_button_(nullptr),
528 close_button_(nullptr), 475 close_button_(nullptr),
529 title_(new views::Label()), 476 title_(new views::Label()),
530 tab_activated_with_last_tap_down_(false), 477 tab_activated_with_last_tap_down_(false),
531 hover_controller_(this), 478 hover_controller_(this),
532 showing_icon_(false), 479 showing_icon_(false),
533 showing_alert_indicator_(false), 480 showing_alert_indicator_(false),
534 showing_close_button_(false), 481 showing_close_button_(false),
535 button_color_(SK_ColorTRANSPARENT) { 482 button_color_(SK_ColorTRANSPARENT) {
536 DCHECK(controller); 483 DCHECK(controller);
537 InitTabResources();
538 484
539 // So we get don't get enter/exit on children and don't prematurely stop the 485 // So we get don't get enter/exit on children and don't prematurely stop the
540 // hover. 486 // hover.
541 set_notify_enter_exit_on_child(true); 487 set_notify_enter_exit_on_child(true);
542 488
543 set_id(VIEW_ID_TAB); 489 set_id(VIEW_ID_TAB);
544 490
545 SetBorder(views::CreateEmptyBorder(GetLayoutInsets(TAB))); 491 SetBorder(views::CreateEmptyBorder(GetLayoutInsets(TAB)));
546 492
547 title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD); 493 title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
(...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after
1116 else 1062 else
1117 StopPulse(); 1063 StopPulse();
1118 } 1064 }
1119 1065
1120 void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) { 1066 void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) {
1121 const int kActiveTabFillId = 1067 const int kActiveTabFillId =
1122 GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR) ? IDR_THEME_TOOLBAR 1068 GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR) ? IDR_THEME_TOOLBAR
1123 : 0; 1069 : 0;
1124 const int y_offset = -GetLayoutInsets(TAB).top(); 1070 const int y_offset = -GetLayoutInsets(TAB).top();
1125 if (IsActive()) { 1071 if (IsActive()) {
1126 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, 1072 PaintTabBackground(canvas, true /* active */, kActiveTabFillId, y_offset,
1127 y_offset); 1073 nullptr /* clip */);
1128 } else { 1074 } else {
1129 PaintInactiveTabBackground(canvas, clip); 1075 PaintInactiveTabBackground(canvas, clip);
1130 1076
1131 const double throb_value = GetThrobValue(); 1077 const double throb_value = GetThrobValue();
1132 if (throb_value > 0) { 1078 if (throb_value > 0) {
1133 canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), 1079 canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff),
1134 GetLocalBounds()); 1080 GetLocalBounds());
1135 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, 1081 PaintTabBackground(canvas, true /* active */, kActiveTabFillId, y_offset,
1136 y_offset); 1082 nullptr /* clip */);
1137 canvas->Restore(); 1083 canvas->Restore();
1138 } 1084 }
1139 } 1085 }
1140 1086
1141 if (showing_icon_) 1087 if (showing_icon_)
1142 PaintIcon(canvas); 1088 PaintIcon(canvas);
1143 } 1089 }
1144 1090
1145 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, 1091 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas,
1146 const gfx::Path& clip) { 1092 const gfx::Path& clip) {
1147 bool has_custom_image; 1093 bool has_custom_image;
1148 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); 1094 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image);
1149 const ui::ThemeProvider* tp = GetThemeProvider();
1150 1095
1151 // We only cache the image when it's the default image and we're not hovered,
1152 // to avoid caching a background image that isn't the same for all tabs.
1153 if (has_custom_image) { 1096 if (has_custom_image) {
1097 const ui::ThemeProvider* tp = GetThemeProvider();
1098
1154 // If the theme is providing a custom background image, then its top edge 1099 // If the theme is providing a custom background image, then its top edge
1155 // should be at the top of the tab. Otherwise, we assume that the background 1100 // should be at the top of the tab. Otherwise, we assume that the background
1156 // image is a composited foreground + frame image. Note that if the theme 1101 // image is a composited foreground + frame image. Note that if the theme
1157 // is only providing a custom frame image, |has_custom_image| will be true, 1102 // is only providing a custom frame image, |has_custom_image| will be true,
1158 // but we should use the |background_offset_| here. 1103 // but we should use the |background_offset_| here.
1159 const int y_offset = 1104 int y_offset = tp->HasCustomImage(fill_id) ? 0 : background_offset_.y();
1160 tp->HasCustomImage(fill_id) ? 0 : background_offset_.y(); 1105 PaintTabBackground(canvas, false /* active */, fill_id, y_offset,
1161 PaintTabBackgroundUsingFillId(canvas, canvas, false, fill_id, y_offset); 1106 nullptr /* clip */);
1162 return; 1107 } else {
1108 PaintTabBackground(canvas, false /* active */, 0 /* fill_id */,
1109 0 /* y_offset */,
1110 controller_->MaySetClip() ? &clip : nullptr);
1163 } 1111 }
1164 if (hover_controller_.ShouldDraw()) { 1112 }
1165 PaintTabBackgroundUsingFillId(canvas, canvas, false, 0, 0); 1113
1114 void Tab::PaintTabBackground(gfx::Canvas* canvas,
1115 bool active,
1116 int fill_id,
1117 int y_offset,
1118 const gfx::Path* clip) {
1119 // |y_offset| is only set when |fill_id| is being used.
1120 DCHECK(!y_offset || !fill_id);
Peter Kasting 2017/04/07 00:59:19 Nit: I'm not sure why this DCHECK is here since, w
danakj 2017/04/07 19:10:49 I added this because I think it should be an invar
danakj 2017/04/07 21:31:08 Oh I had the logic inverted though. I miss DCHECK_
1121
1122 const ui::ThemeProvider* tp = GetThemeProvider();
1123 SkColor active_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);
Peter Kasting 2017/04/07 00:59:19 Nit: These could all be const
danakj 2017/04/07 19:10:49 Sure, I guess I don't see much reason for putting
1124 SkColor inactive_color = tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB);
1125 bool hover = !active && hover_controller_.ShouldDraw();
1126
1127 // If there is a |fill_id| we don't try to cache. This could be improved
1128 // but would require knowing then the image from the ThemeProvider had been
1129 // changed, and invalidating when more position values changed.
Peter Kasting 2017/04/07 00:59:19 Nit: more position values changed -> the X coordin
danakj 2017/04/07 19:10:49 Also background_offset_ (both x() which is used di
1130 // Stroke does not depend on |fill_id|.
1131 // Similarly, if |hover| effects should be shown, we don't try to cache since
1132 // they change on every invalidation and we would need to invalidate the cache
1133 // based on the hover states.
1134 if (fill_id || hover) {
1135 gfx::Path fill_path = GetFillPath(canvas->image_scale(), size());
1136 PaintTabBackgroundFill(canvas, fill_path, active, hover, active_color,
1137 inactive_color, fill_id, y_offset);
1138 gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
1139 if (clip)
1140 canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
Peter Kasting 2017/04/07 00:59:19 These bits about scoping a canvas, then clipping,
danakj 2017/04/07 19:10:49 It's a nice thought, the problem is we have to cha
Peter Kasting 2017/04/08 00:59:37 The way I can think of, which may not be a win, is
1141 PaintTabBackgroundStroke(canvas, fill_path, active);
1166 return; 1142 return;
1167 } 1143 }
1168 1144
1169 // For efficiency, we don't use separate fill and stroke images unless we 1145 BackgroundCache& cache =
1170 // really need to clip the stroke and not the fill (for stacked tabs). This 1146 active ? background_active_cache_ : background_inactive_cache_;
1171 // saves memory and avoids an extra image draw at the cost of recalculating 1147 bool matches_cache = cache.scale == canvas->image_scale() &&
Peter Kasting 2017/04/07 00:59:19 Nit: I liked how the old code had a metadata struc
danakj 2017/04/07 19:10:49 It feels like it should be less, but It's a more l
Peter Kasting 2017/04/07 23:34:03 It's definitely more verbose overall. I'm OK with
danakj 2017/04/18 16:02:42 The duplicate storage I mean like.. float scale
1172 // the images when MaySetClip() toggles. 1148 cache.size == size() &&
1173 const bool use_fill_and_stroke_images = controller_->MaySetClip(); 1149 cache.active_color == active_color &&
1150 cache.inactive_color == inactive_color;
1151 if (!matches_cache) {
1152 gfx::Path fill_path = GetFillPath(canvas->image_scale(), size());
1153 cc::PaintRecorder recorder;
1174 1154
1175 const ImageCacheEntryMetadata metadata( 1155 {
1176 tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), 1156 gfx::Canvas cache_canvas(
1177 controller_->GetToolbarTopSeparatorColor(), use_fill_and_stroke_images, 1157 recorder.beginRecording(size().width(), size().height()),
1178 canvas->image_scale(), size()); 1158 canvas->image_scale());
1179 auto it = std::find_if( 1159 PaintTabBackgroundFill(&cache_canvas, fill_path, active, hover,
1180 g_image_cache->begin(), g_image_cache->end(), 1160 active_color, inactive_color, fill_id, y_offset);
1181 [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; }); 1161 cache.fill_record = recorder.finishRecordingAsPicture();
1182 if (it == g_image_cache->end()) {
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 } 1162 }
1196 if (g_image_cache->size() > kMaxImageCacheSize) 1163 {
1197 g_image_cache->pop_back(); 1164 gfx::Canvas cache_canvas(
1198 it = g_image_cache->begin(); 1165 recorder.beginRecording(size().width(), size().height()),
1166 canvas->image_scale());
1167 PaintTabBackgroundStroke(canvas, fill_path, active);
1168 cache.stroke_record = recorder.finishRecordingAsPicture();
1169 }
1170
1171 cache.scale = canvas->image_scale();
1172 cache.size = size();
1173 cache.active_color = active_color;
1174 cache.inactive_color = inactive_color;
1199 } 1175 }
1200 1176
1201 gfx::ScopedCanvas scoped_canvas( 1177 canvas->sk_canvas()->PlaybackPaintRecord(cache.fill_record);
1202 use_fill_and_stroke_images ? canvas : nullptr); 1178 gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
1203 if (use_fill_and_stroke_images) { 1179 if (clip)
1204 canvas->DrawImageInt(it->fill_image, 0, 0); 1180 canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
1205 canvas->sk_canvas()->clipPath(clip, SkClipOp::kDifference, true); 1181 canvas->sk_canvas()->PlaybackPaintRecord(cache.stroke_record);
1206 }
1207 canvas->DrawImageInt(it->stroke_image, 0, 0);
1208 } 1182 }
1209 1183
1210 void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas, 1184 void Tab::PaintTabBackgroundFill(gfx::Canvas* canvas,
1211 gfx::Canvas* stroke_canvas, 1185 const gfx::Path& fill_path,
1212 bool is_active, 1186 bool active,
1213 int fill_id, 1187 bool hover,
1214 int y_offset) { 1188 SkColor active_color,
1215 gfx::Path fill; 1189 SkColor inactive_color,
1216 cc::PaintFlags flags; 1190 int fill_id,
1217 flags.setAntiAlias(true); 1191 int y_offset) {
1192 gfx::ScopedCanvas scoped_canvas(canvas);
1193 const float scale = canvas->UndoDeviceScaleFactor();
1218 1194
1219 // Draw the fill. 1195 canvas->ClipPath(fill_path, true);
1220 { 1196 if (fill_id) {
1221 gfx::ScopedCanvas scoped_canvas(fill_canvas);
1222 const float scale = fill_canvas->UndoDeviceScaleFactor();
1223 const ui::ThemeProvider* tp = GetThemeProvider(); 1197 const ui::ThemeProvider* tp = GetThemeProvider();
Peter Kasting 2017/04/07 00:59:19 Nit: Just inline this below?
danakj 2017/04/07 19:10:49 Done.
1224 const SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);
1225 1198
1226 fill = GetFillPath(scale, size()); 1199 gfx::ScopedCanvas scale_scoper(canvas);
1227 { 1200 canvas->sk_canvas()->scale(scale, scale);
1228 gfx::ScopedCanvas clip_scoper(fill_canvas); 1201 canvas->TileImageInt(*tp->GetImageSkiaNamed(fill_id),
1229 fill_canvas->ClipPath(fill, true); 1202 GetMirroredX() + background_offset_.x(), y_offset, 0,
1230 if (fill_id) { 1203 0, width(), height());
1231 gfx::ScopedCanvas scale_scoper(fill_canvas); 1204 } else {
1232 fill_canvas->sk_canvas()->scale(scale, scale); 1205 cc::PaintFlags flags;
1233 fill_canvas->TileImageInt(*tp->GetImageSkiaNamed(fill_id), 1206 flags.setAntiAlias(true);
1234 GetMirroredX() + background_offset_.x(), 1207 flags.setColor(active ? active_color : inactive_color);
1235 y_offset, 0, 0, width(), height()); 1208 canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), flags);
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 } 1209 }
1256 1210
1257 // Draw the stroke. 1211 if (hover) {
Peter Kasting 2017/04/07 00:59:20 Nit: Maybe name this |draw_highlight| or |draw_hov
danakj 2017/04/07 19:10:49 went with paint_hover_effect. "draw" is a overload
1258 { 1212 SkPoint hover_location(gfx::PointToSkPoint(hover_controller_.location()));
1259 gfx::ScopedCanvas scoped_canvas(stroke_canvas); 1213 hover_location.scale(SkFloatToScalar(scale));
1260 const float scale = stroke_canvas->UndoDeviceScaleFactor(); 1214 const SkScalar kMinHoverRadius = 16;
1261 1215 const SkScalar radius =
1262 gfx::Path stroke = GetBorderPath(scale, false, false, size()); 1216 std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius);
1263 Op(stroke, fill, kDifference_SkPathOp, &stroke); 1217 DrawHighlight(canvas, hover_location, radius * scale,
1264 if (!is_active) { 1218 SkColorSetA(active_color, hover_controller_.GetAlpha()));
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 } 1219 }
1273 } 1220 }
1274 1221
1222 void Tab::PaintTabBackgroundStroke(gfx::Canvas* canvas,
1223 const gfx::Path& fill_path,
1224 bool active) {
1225 SkColor color = controller_->GetToolbarTopSeparatorColor();
1226
1227 gfx::ScopedCanvas scoped_canvas(canvas);
1228 const float scale = canvas->UndoDeviceScaleFactor();
1229
1230 gfx::Path stroke = GetBorderPath(scale, false, false, size());
1231 Op(stroke, fill_path, kDifference_SkPathOp, &stroke);
1232 if (!active) {
1233 // Clip out the bottom line; this will be drawn for us by
1234 // TabStrip::PaintChildren().
1235 canvas->ClipRect(gfx::RectF(width() * scale, height() * scale - 1));
1236 }
1237 cc::PaintFlags flags;
1238 flags.setAntiAlias(true);
1239 flags.setColor(color);
1240 canvas->DrawPath(stroke, flags);
1241 }
1242
1275 void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon( 1243 void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon(
1276 gfx::Canvas* canvas, 1244 gfx::Canvas* canvas,
1277 const gfx::Rect& favicon_draw_bounds) { 1245 const gfx::Rect& favicon_draw_bounds) {
1278 // The pinned tab title changed indicator consists of two parts: 1246 // The pinned tab title changed indicator consists of two parts:
1279 // . a clear (totally transparent) part over the bottom right (or left in rtl) 1247 // . 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 canvas, then 1248 // of the favicon. This is done by drawing the favicon to a canvas, then
1281 // drawing the clear part on top of the favicon. 1249 // drawing the clear part on top of the favicon.
1282 // . a circle in the bottom right (or left in rtl) of the favicon. 1250 // . a circle in the bottom right (or left in rtl) of the favicon.
1283 if (!favicon_.isNull()) { 1251 if (!favicon_.isNull()) {
1284 const float kIndicatorCropRadius = 4.5; 1252 const float kIndicatorCropRadius = 4.5;
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
1486 gfx::Rect bounds = favicon_bounds_; 1454 gfx::Rect bounds = favicon_bounds_;
1487 if (bounds.IsEmpty()) 1455 if (bounds.IsEmpty())
1488 return; 1456 return;
1489 1457
1490 // Extends the area to the bottom when the crash animation is in progress. 1458 // Extends the area to the bottom when the crash animation is in progress.
1491 if (crash_icon_animation_->is_animating()) 1459 if (crash_icon_animation_->is_animating())
1492 bounds.set_height(height() - bounds.y()); 1460 bounds.set_height(height() - bounds.y());
1493 bounds.set_x(GetMirroredXForRect(bounds)); 1461 bounds.set_x(GetMirroredXForRect(bounds));
1494 SchedulePaintInRect(bounds); 1462 SchedulePaintInRect(bounds);
1495 } 1463 }
1464
1465 Tab::BackgroundCache::BackgroundCache() = default;
1466 Tab::BackgroundCache::~BackgroundCache() = default;
OLDNEW
« chrome/browser/ui/views/tabs/tab.h ('K') | « chrome/browser/ui/views/tabs/tab.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698