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

Unified Diff: chrome/browser/ui/views/tabs/tab.cc

Issue 2803583003: ui: Remove use of bitmaps when painting tab backgrounds. (Closed)
Patch Set: tabbackground: . 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/views/tabs/tab.cc
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 36cc8cd5388f55619ae37abd035f03d83eaee74c..9935918534e08b7cc369f669c6e3b861eef1e444 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -14,7 +14,8 @@
#include "base/metrics/user_metrics.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "cc/paint/paint_shader.h"
+#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_recorder.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/browser.h"
@@ -93,95 +94,9 @@ const double kSelectedTabOpacity = 0.3;
// Inactive selected tabs have their throb value scaled by this.
const double kSelectedTabThrobScale = 0.95 - kSelectedTabOpacity;
-// Max number of images to cache. This has to be at least two since rounding
-// errors may lead to tabs in the same tabstrip having different sizes.
-// 8 = normal/incognito, active/inactive, 2 sizes within tabstrip.
-const size_t kMaxImageCacheSize = 8;
-
const char kTabCloseButtonName[] = "TabCloseButton";
////////////////////////////////////////////////////////////////////////////////
-// ImageCacheEntryMetadata
-//
-// All metadata necessary to uniquely identify a cached image.
-struct ImageCacheEntryMetadata {
- ImageCacheEntryMetadata(SkColor fill_color,
- SkColor stroke_color,
- bool use_fill_and_stroke_images,
- float scale_factor,
- const gfx::Size& size);
-
- ~ImageCacheEntryMetadata();
-
- bool operator==(const ImageCacheEntryMetadata& rhs) const;
-
- SkColor fill_color;
- SkColor stroke_color;
- bool use_fill_and_stroke_images;
- float scale_factor;
- gfx::Size size;
-};
-
-ImageCacheEntryMetadata::ImageCacheEntryMetadata(
- SkColor fill_color,
- SkColor stroke_color,
- bool use_fill_and_stroke_images,
- float scale_factor,
- const gfx::Size& size)
- : fill_color(fill_color),
- stroke_color(stroke_color),
- use_fill_and_stroke_images(use_fill_and_stroke_images),
- scale_factor(scale_factor),
- size(size) {}
-
-ImageCacheEntryMetadata::~ImageCacheEntryMetadata() {}
-
-bool ImageCacheEntryMetadata::operator==(
- const ImageCacheEntryMetadata& rhs) const {
- return fill_color == rhs.fill_color && stroke_color == rhs.stroke_color &&
- use_fill_and_stroke_images == rhs.use_fill_and_stroke_images &&
- scale_factor == rhs.scale_factor && size == rhs.size;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ImageCacheEntry and cache management
-//
-// A cached image and the metadata used to generate it.
-struct ImageCacheEntry {
- ImageCacheEntry(const ImageCacheEntryMetadata& metadata,
- const gfx::ImageSkia& fill_image,
- const gfx::ImageSkia& stroke_image);
- ~ImageCacheEntry();
-
- ImageCacheEntryMetadata metadata;
- gfx::ImageSkia fill_image;
- gfx::ImageSkia stroke_image;
-};
-
-ImageCacheEntry::ImageCacheEntry(const ImageCacheEntryMetadata& metadata,
- const gfx::ImageSkia& fill_image,
- const gfx::ImageSkia& stroke_image)
- : metadata(metadata), fill_image(fill_image), stroke_image(stroke_image) {}
-
-ImageCacheEntry::~ImageCacheEntry() {}
-
-typedef std::list<ImageCacheEntry> ImageCache;
-
-// As the majority of the tabs are inactive, and painting tabs is slowish,
-// we cache a handful of the inactive tab backgrounds here.
-static ImageCache* g_image_cache = nullptr;
-
-// Performs a one-time initialization of static resources such as tab images.
-void InitTabResources() {
- static bool initialized = false;
- if (initialized)
- return;
-
- initialized = true;
- g_image_cache = new ImageCache();
-}
-
-////////////////////////////////////////////////////////////////////////////////
// Drawing and utility functions
// Returns the width of the tab endcap at scale 1. More precisely, this is the
@@ -534,7 +449,6 @@ Tab::Tab(TabController* controller, gfx::AnimationContainer* container)
showing_close_button_(false),
button_color_(SK_ColorTRANSPARENT) {
DCHECK(controller);
- InitTabResources();
// So we get don't get enter/exit on children and don't prematurely stop the
// hover.
@@ -1118,13 +1032,16 @@ void Tab::DataChanged(const TabRendererData& old) {
}
void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) {
- const int kActiveTabFillId =
- GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR) ? IDR_THEME_TOOLBAR
- : 0;
- const int y_offset = -GetLayoutInsets(TAB).top();
+ int active_tab_fill_id = 0;
+ int active_tab_y_offset = 0;
+ if (GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR)) {
+ active_tab_fill_id = IDR_THEME_TOOLBAR;
+ active_tab_y_offset = -GetLayoutInsets(TAB).top();
+ }
+
if (IsActive()) {
- PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId,
- y_offset);
+ PaintTabBackground(canvas, true /* active */, active_tab_fill_id,
+ active_tab_y_offset, nullptr /* clip */);
} else {
PaintInactiveTabBackground(canvas, clip);
@@ -1132,8 +1049,8 @@ void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) {
if (throb_value > 0) {
canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff),
GetLocalBounds());
- PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId,
- y_offset);
+ PaintTabBackground(canvas, true /* active */, active_tab_fill_id,
+ active_tab_y_offset, nullptr /* clip */);
canvas->Restore();
}
}
@@ -1146,132 +1063,154 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas,
const gfx::Path& clip) {
bool has_custom_image;
int fill_id = controller_->GetBackgroundResourceId(&has_custom_image);
- const ui::ThemeProvider* tp = GetThemeProvider();
- // We only cache the image when it's the default image and we're not hovered,
- // to avoid caching a background image that isn't the same for all tabs.
- if (has_custom_image) {
- // If the theme is providing a custom background image, then its top edge
- // should be at the top of the tab. Otherwise, we assume that the background
- // image is a composited foreground + frame image. Note that if the theme
- // is only providing a custom frame image, |has_custom_image| will be true,
- // but we should use the |background_offset_| here.
- const int y_offset =
- tp->HasCustomImage(fill_id) ? 0 : background_offset_.y();
- PaintTabBackgroundUsingFillId(canvas, canvas, false, fill_id, y_offset);
- return;
- }
- if (hover_controller_.ShouldDraw()) {
- PaintTabBackgroundUsingFillId(canvas, canvas, false, 0, 0);
- return;
- }
+ // The offset used to read from the image specified by |fill_id|.
+ int y_offset = 0;
- // For efficiency, we don't use separate fill and stroke images unless we
- // really need to clip the stroke and not the fill (for stacked tabs). This
- // saves memory and avoids an extra image draw at the cost of recalculating
- // the images when MaySetClip() toggles.
- const bool use_fill_and_stroke_images = controller_->MaySetClip();
-
- const ImageCacheEntryMetadata metadata(
- tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB),
- controller_->GetToolbarTopSeparatorColor(), use_fill_and_stroke_images,
- canvas->image_scale(), size());
- auto it = std::find_if(
- g_image_cache->begin(), g_image_cache->end(),
- [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; });
- if (it == g_image_cache->end()) {
- gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false);
- if (use_fill_and_stroke_images) {
- gfx::Canvas tmp_fill_canvas(size(), canvas->image_scale(), false);
- PaintTabBackgroundUsingFillId(&tmp_fill_canvas, &tmp_canvas, false, 0, 0);
- g_image_cache->emplace_front(
- metadata, gfx::ImageSkia(tmp_fill_canvas.ExtractImageRep()),
- gfx::ImageSkia(tmp_canvas.ExtractImageRep()));
- } else {
- PaintTabBackgroundUsingFillId(&tmp_canvas, &tmp_canvas, false, 0, 0);
- g_image_cache->emplace_front(
- metadata, gfx::ImageSkia(),
- gfx::ImageSkia(tmp_canvas.ExtractImageRep()));
- }
- if (g_image_cache->size() > kMaxImageCacheSize)
- g_image_cache->pop_back();
- it = g_image_cache->begin();
+ if (!has_custom_image) {
+ fill_id = 0;
+ } else if (!GetThemeProvider()->HasCustomImage(fill_id)) {
+ // If there's a custom frame image but no custom image for the tab itself,
+ // then the tab's background will be the frame's image, so we need to
+ // provide an offset into the image to read from.
+ y_offset = background_offset_.y();
}
- gfx::ScopedCanvas scoped_canvas(
- use_fill_and_stroke_images ? canvas : nullptr);
- if (use_fill_and_stroke_images) {
- canvas->DrawImageInt(it->fill_image, 0, 0);
- canvas->sk_canvas()->clipPath(clip, SkClipOp::kDifference, true);
- }
- canvas->DrawImageInt(it->stroke_image, 0, 0);
+ PaintTabBackground(canvas, false /* active */, fill_id, y_offset,
+ controller_->MaySetClip() ? &clip : nullptr);
}
-void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas,
- gfx::Canvas* stroke_canvas,
- bool is_active,
- int fill_id,
- int y_offset) {
- gfx::Path fill;
- cc::PaintFlags flags;
- flags.setAntiAlias(true);
+void Tab::PaintTabBackground(gfx::Canvas* canvas,
+ bool active,
+ int fill_id,
+ int y_offset,
+ const gfx::Path* clip) {
+ // |y_offset| is only set when |fill_id| is being used.
+ DCHECK(!y_offset || fill_id);
+
+ const ui::ThemeProvider* tp = GetThemeProvider();
+ const SkColor active_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);
+ const SkColor inactive_color =
+ tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB);
+ const SkColor stroke_color = controller_->GetToolbarTopSeparatorColor();
+ const bool paint_hover_effect = !active && hover_controller_.ShouldDraw();
+
+ // If there is a |fill_id| we don't try to cache. This could be improved
+ // but would require knowing then the image from the ThemeProvider had been
+ // changed, and invalidating when the tab's x-coordinate or background_offset_
+ // changed.
+ // Similarly, if |paint_hover_effect|, we don't try to cache since hover
+ // effects change on every invalidation and we would need to invalidate the
+ // cache based on the hover states.
+ if (fill_id || paint_hover_effect) {
+ gfx::Path fill_path = GetFillPath(canvas->image_scale(), size());
+ gfx::Path stroke_path =
+ GetBorderPath(canvas->image_scale(), false, false, size());
+ PaintTabBackgroundFill(canvas, fill_path, active, paint_hover_effect,
+ active_color, inactive_color, fill_id, y_offset);
+ gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
+ if (clip)
+ canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
+ PaintTabBackgroundStroke(canvas, fill_path, stroke_path, active,
+ stroke_color);
+ return;
+ }
- // Draw the fill.
- {
- gfx::ScopedCanvas scoped_canvas(fill_canvas);
- const float scale = fill_canvas->UndoDeviceScaleFactor();
- const ui::ThemeProvider* tp = GetThemeProvider();
- const SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);
+ BackgroundCache& cache =
+ active ? background_active_cache_ : background_inactive_cache_;
+ if (!cache.CacheKeyMatches(canvas->image_scale(), size(), active_color,
+ inactive_color, stroke_color)) {
+ gfx::Path fill_path = GetFillPath(canvas->image_scale(), size());
+ gfx::Path stroke_path =
+ GetBorderPath(canvas->image_scale(), false, false, size());
+ cc::PaintRecorder recorder;
- fill = GetFillPath(scale, size());
{
- gfx::ScopedCanvas clip_scoper(fill_canvas);
- fill_canvas->ClipPath(fill, true);
- if (fill_id) {
- gfx::ScopedCanvas scale_scoper(fill_canvas);
- fill_canvas->sk_canvas()->scale(scale, scale);
- fill_canvas->TileImageInt(*tp->GetImageSkiaNamed(fill_id),
- GetMirroredX() + background_offset_.x(),
- y_offset, 0, 0, width(), height());
- } else {
- flags.setColor(
- is_active ? toolbar_color
- : tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB));
- fill_canvas->DrawRect(
- gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), flags);
- }
-
- if (!is_active && hover_controller_.ShouldDraw()) {
- SkPoint hover_location(
- gfx::PointToSkPoint(hover_controller_.location()));
- hover_location.scale(SkFloatToScalar(scale));
- const SkScalar kMinHoverRadius = 16;
- const SkScalar radius =
- std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius);
- DrawHighlight(fill_canvas, hover_location, radius * scale,
- SkColorSetA(toolbar_color, hover_controller_.GetAlpha()));
- }
+ gfx::Canvas cache_canvas(
+ recorder.beginRecording(size().width(), size().height()),
+ canvas->image_scale());
+ PaintTabBackgroundFill(&cache_canvas, fill_path, active,
+ paint_hover_effect, active_color, inactive_color,
+ fill_id, y_offset);
+ cache.fill_record = recorder.finishRecordingAsPicture();
}
+ {
+ gfx::Canvas cache_canvas(
+ recorder.beginRecording(size().width(), size().height()),
+ canvas->image_scale());
+ PaintTabBackgroundStroke(&cache_canvas, fill_path, stroke_path, active,
+ stroke_color);
+ cache.stroke_record = recorder.finishRecordingAsPicture();
+ }
+
+ cache.SetCacheKey(canvas->image_scale(), size(), active_color,
+ inactive_color, stroke_color);
}
- // Draw the stroke.
- {
- gfx::ScopedCanvas scoped_canvas(stroke_canvas);
- const float scale = stroke_canvas->UndoDeviceScaleFactor();
-
- gfx::Path stroke = GetBorderPath(scale, false, false, size());
- Op(stroke, fill, kDifference_SkPathOp, &stroke);
- if (!is_active) {
- // Clip out the bottom line; this will be drawn for us by
- // TabStrip::PaintChildren().
- stroke_canvas->ClipRect(
- gfx::RectF(width() * scale, height() * scale - 1));
- }
- flags.setColor(controller_->GetToolbarTopSeparatorColor());
- stroke_canvas->DrawPath(stroke, flags);
+ canvas->sk_canvas()->PlaybackPaintRecord(cache.fill_record);
+ gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
+ if (clip)
+ canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
+ canvas->sk_canvas()->PlaybackPaintRecord(cache.stroke_record);
+}
+
+void Tab::PaintTabBackgroundFill(gfx::Canvas* canvas,
+ const gfx::Path& fill_path,
+ bool active,
+ bool paint_hover_effect,
+ SkColor active_color,
+ SkColor inactive_color,
+ int fill_id,
+ int y_offset) {
+ gfx::ScopedCanvas scoped_canvas(canvas);
+ const float scale = canvas->UndoDeviceScaleFactor();
+
+ canvas->ClipPath(fill_path, true);
+ if (fill_id) {
+ gfx::ScopedCanvas scale_scoper(canvas);
+ canvas->sk_canvas()->scale(scale, scale);
+ canvas->TileImageInt(*GetThemeProvider()->GetImageSkiaNamed(fill_id),
+ GetMirroredX() + background_offset_.x(), y_offset, 0,
+ 0, width(), height());
+ } else {
+ cc::PaintFlags flags;
+ flags.setAntiAlias(true);
+ flags.setColor(active ? active_color : inactive_color);
+ canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), flags);
+ }
+
+ if (paint_hover_effect) {
+ SkPoint hover_location(gfx::PointToSkPoint(hover_controller_.location()));
+ hover_location.scale(SkFloatToScalar(scale));
+ const SkScalar kMinHoverRadius = 16;
+ const SkScalar radius =
+ std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius);
+ DrawHighlight(canvas, hover_location, radius * scale,
+ SkColorSetA(active_color, hover_controller_.GetAlpha()));
}
}
+void Tab::PaintTabBackgroundStroke(gfx::Canvas* canvas,
+ const gfx::Path& fill_path,
+ const gfx::Path& stroke_path,
+ bool active,
+ SkColor color) {
+ gfx::ScopedCanvas scoped_canvas(canvas);
+ const float scale = canvas->UndoDeviceScaleFactor();
+
+ if (!active) {
+ // Clip out the bottom line; this will be drawn for us by
+ // TabStrip::PaintChildren().
+ canvas->ClipRect(gfx::RectF(width() * scale, height() * scale - 1));
+ }
+ cc::PaintFlags flags;
+ flags.setAntiAlias(true);
+ flags.setColor(color);
+ SkPath path;
+ Op(stroke_path, fill_path, kDifference_SkPathOp, &path);
+ canvas->DrawPath(path, flags);
+}
+
void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon(
gfx::Canvas* canvas,
const gfx::Rect& favicon_draw_bounds) {
@@ -1493,3 +1432,6 @@ void Tab::ScheduleIconPaint() {
bounds.set_x(GetMirroredXForRect(bounds));
SchedulePaintInRect(bounds);
}
+
+Tab::BackgroundCache::BackgroundCache() = default;
+Tab::BackgroundCache::~BackgroundCache() = default;
« no previous file with comments | « 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