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 90d920f8597577eec5f15674290b36c4e1b04d36..d0e2138483633f7b62009d81834dc7299bd1b65d 100644 |
--- a/chrome/browser/ui/views/tabs/tab.cc |
+++ b/chrome/browser/ui/views/tabs/tab.cc |
@@ -44,6 +44,7 @@ |
#include "ui/gfx/color_analysis.h" |
#include "ui/gfx/favicon_size.h" |
#include "ui/gfx/geometry/rect_conversions.h" |
+#include "ui/gfx/image/canvas_image_source.h" |
#include "ui/gfx/image/image_skia_operations.h" |
#include "ui/gfx/paint_vector_icon.h" |
#include "ui/gfx/path.h" |
@@ -121,32 +122,93 @@ const double kDesaturateHue = -1.0; |
const double kDesaturateSaturation = 0.0; |
const double kDesaturateLightness = 0.6; |
-// Parameters for PaintTabBackgroundUsingParams(). |
+// Parameters for PaintTabFill/StrokeUsingParams(). |
struct PaintBackgroundParams { |
PaintBackgroundParams(bool is_active, |
- gfx::ImageSkia* fill_image_ptr, |
+ gfx::ImageSkia* fill_image, |
bool has_custom_image, |
- gfx::Rect rect, |
+ const gfx::Rect& rect, |
SkColor stroke_color, |
SkColor toolbar_color, |
- SkColor background_tab_color) |
+ SkColor background_tab_color, |
+ bool draw_hover, |
+ const gfx::Point& hover_location, |
+ SkAlpha hover_alpha) |
: is_active(is_active), |
- fill_image(fill_image_ptr ? *fill_image_ptr : gfx::ImageSkia()), |
- has_custom_image(has_custom_image), |
+ fill_image(fill_image ? *fill_image : gfx::ImageSkia()), |
rect(rect), |
stroke_color(stroke_color), |
toolbar_color(toolbar_color), |
- background_tab_color(background_tab_color) {} |
+ background_tab_color(background_tab_color), |
+ draw_hover(draw_hover), |
+ hover_location(PointToSkPoint(hover_location)), |
+ hover_alpha(hover_alpha) {} |
const bool is_active; |
const gfx::ImageSkia fill_image; |
- const bool has_custom_image; |
const gfx::Rect rect; |
const SkColor stroke_color; |
const SkColor toolbar_color; |
const SkColor background_tab_color; |
+ const bool draw_hover; |
+ const SkPoint hover_location; |
+ const SkAlpha hover_alpha; |
}; |
+void PaintTabFillUsingParams(gfx::Canvas* canvas, |
+ const PaintBackgroundParams& params); |
+ |
+void PaintTabStrokeUsingParams(gfx::Canvas* canvas, |
+ const PaintBackgroundParams& params); |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// TabImageSource |
+// |
+// This subclass of CanvasImageSource allows the inactive tab image to be cached |
+// once for each requested scale factor. |
+class TabImageSource : public gfx::CanvasImageSource { |
+ public: |
+ enum UseCanvas { FILL, STROKE, BOTH }; |
+ |
+ TabImageSource(UseCanvas use_canvas, Tab* tab, int fill_id, int y_offset); |
+ ~TabImageSource() override {} |
+ |
+ // gfx::CanvasImageSource override. |
+ void Draw(gfx::Canvas* canvas) override; |
+ bool HasRepresentationAtAllScales() const override { return true; } |
+ |
+ private: |
+ const UseCanvas use_canvas_; |
+ const PaintBackgroundParams params_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TabImageSource); |
+}; |
+ |
+TabImageSource::TabImageSource(UseCanvas use_canvas, |
+ Tab* tab, |
+ int fill_id, |
+ int y_offset) |
+ : gfx::CanvasImageSource(tab->size(), true), |
+ use_canvas_(use_canvas), |
+ params_(false, |
+ tab->GetThemeProvider()->GetImageSkiaNamed(fill_id), |
+ false, |
+ gfx::Rect(gfx::Point(0, y_offset), tab->size()), |
+ tab->controller()->GetToolbarTopSeparatorColor(), |
+ tab->GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR), |
+ tab->GetThemeProvider()->GetColor( |
+ ThemeProperties::COLOR_BACKGROUND_TAB), |
+ false, |
+ gfx::Point(), |
+ 255) {} |
+ |
+void TabImageSource::Draw(gfx::Canvas* canvas) { |
+ if (use_canvas_ != STROKE) |
+ PaintTabFillUsingParams(canvas, params_); |
+ if (use_canvas_ != FILL) |
+ PaintTabStrokeUsingParams(canvas, params_); |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// ImageCacheEntryMetadata |
// |
@@ -156,7 +218,6 @@ struct ImageCacheEntryMetadata { |
SkColor fill_color, |
SkColor stroke_color, |
bool use_fill_and_stroke_images, |
- ui::ScaleFactor scale_factor, |
const gfx::Size& size); |
~ImageCacheEntryMetadata(); |
@@ -167,7 +228,6 @@ struct ImageCacheEntryMetadata { |
SkColor fill_color; // Both colors only needed by MD |
SkColor stroke_color; |
bool use_fill_and_stroke_images; |
- ui::ScaleFactor scale_factor; |
gfx::Size size; |
}; |
@@ -176,16 +236,12 @@ ImageCacheEntryMetadata::ImageCacheEntryMetadata( |
SkColor fill_color, |
SkColor stroke_color, |
bool use_fill_and_stroke_images, |
- ui::ScaleFactor scale_factor, |
const gfx::Size& size) |
: resource_id(resource_id), |
fill_color(fill_color), |
stroke_color(stroke_color), |
use_fill_and_stroke_images(use_fill_and_stroke_images), |
- scale_factor(scale_factor), |
size(size) { |
- DCHECK_NE(ui::SCALE_FACTOR_NONE, scale_factor); |
- |
// Some fields are only relevant for pre-MD vs. MD. Erase the irrelevant ones |
// so they don't cause incorrect cache misses. |
// TODO(pkasting): Remove |resource_id| field when non-MD code is deleted. |
@@ -202,7 +258,7 @@ bool ImageCacheEntryMetadata::operator==( |
return resource_id == rhs.resource_id && 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; |
+ size == rhs.size; |
} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -211,8 +267,9 @@ bool ImageCacheEntryMetadata::operator==( |
// 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); |
+ Tab* tab, |
+ int fill_id, |
+ int y_offset); |
~ImageCacheEntry(); |
ImageCacheEntryMetadata metadata; |
@@ -221,9 +278,21 @@ struct ImageCacheEntry { |
}; |
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) {} |
+ Tab* tab, |
+ int fill_id, |
+ int y_offset) |
+ : metadata(metadata) { |
+ if (metadata.use_fill_and_stroke_images) { |
+ fill_image = gfx::ImageSkia( |
+ new TabImageSource(TabImageSource::FILL, tab, fill_id, y_offset), |
+ tab->size()); |
+ } |
+ TabImageSource::UseCanvas use = metadata.use_fill_and_stroke_images |
+ ? TabImageSource::STROKE |
+ : TabImageSource::BOTH; |
+ stroke_image = gfx::ImageSkia(new TabImageSource(use, tab, fill_id, y_offset), |
+ tab->size()); |
+} |
ImageCacheEntry::~ImageCacheEntry() {} |
@@ -486,73 +555,45 @@ void PaintTabFill(gfx::Canvas* canvas, |
tab_insets.top(), rect.width(), rect.height()); |
} |
-void PaintTabBackgroundUsingParams(gfx::Canvas* fill_canvas, |
- gfx::Canvas* stroke_canvas, |
- views::GlowHoverController* hc, |
- const PaintBackgroundParams& params) { |
+// In non-MD mode, there is never a need to draw fill and stroke onto separate |
+// canvases, so in that case, this function does both. |
+void PaintTabFillUsingParams(gfx::Canvas* canvas, |
+ const PaintBackgroundParams& params) { |
const gfx::Rect& rect = params.rect; |
const SkScalar kMinHoverRadius = 16; |
const SkScalar radius = |
std::max(SkFloatToScalar(rect.width() / 4.f), kMinHoverRadius); |
- const bool draw_hover = !params.is_active && hc; |
- SkPoint hover_location( |
- gfx::PointToSkPoint(draw_hover ? hc->location() : gfx::Point())); |
const SkColor hover_color = |
- SkColorSetA(params.toolbar_color, draw_hover ? hc->GetAlpha() : 255); |
+ SkColorSetA(params.toolbar_color, params.hover_alpha); |
if (ui::MaterialDesignController::IsModeMaterial()) { |
- gfx::Path fill; |
- SkPaint paint; |
- paint.setAntiAlias(true); |
+ gfx::ScopedCanvas scoped_canvas(canvas); |
+ const float scale = canvas->UndoDeviceScaleFactor(); |
+ gfx::Path fill = GetFillPath(scale, rect.size()); |
- // Draw the fill. |
{ |
- gfx::ScopedCanvas scoped_canvas(fill_canvas); |
- const float scale = fill_canvas->UndoDeviceScaleFactor(); |
- |
- fill = GetFillPath(scale, rect.size()); |
- { |
- gfx::ScopedCanvas clip_scoper(fill_canvas); |
- fill_canvas->ClipPath(fill, true); |
- if (!params.fill_image.isNull()) { |
- gfx::ScopedCanvas scale_scoper(fill_canvas); |
- fill_canvas->sk_canvas()->scale(scale, scale); |
- fill_canvas->TileImageInt(params.fill_image, rect.x(), rect.y(), 0, 0, |
- rect.width(), rect.height()); |
- } else { |
- paint.setColor(params.is_active ? params.toolbar_color |
- : params.background_tab_color); |
- fill_canvas->DrawRect( |
- gfx::ScaleToEnclosingRect(gfx::Rect(rect.size()), scale), |
- paint); |
- } |
- if (draw_hover) { |
- hover_location.scale(SkFloatToScalar(scale)); |
- DrawHighlight(fill_canvas, hover_location, radius * scale, |
- hover_color); |
- } |
+ gfx::ScopedCanvas clip_scoper(canvas); |
+ canvas->ClipPath(fill, true); |
+ if (!params.fill_image.isNull()) { |
+ gfx::ScopedCanvas scale_scoper(canvas); |
+ canvas->sk_canvas()->scale(scale, scale); |
+ canvas->TileImageInt(params.fill_image, rect.x(), rect.y(), 0, 0, |
+ rect.width(), rect.height()); |
+ } else { |
+ SkPaint paint; |
+ paint.setAntiAlias(true); |
+ paint.setColor(params.is_active ? params.toolbar_color |
+ : params.background_tab_color); |
+ canvas->DrawRect( |
+ gfx::ScaleToEnclosingRect(gfx::Rect(rect.size()), scale), paint); |
} |
- } |
- |
- // Draw the stroke. |
- { |
- gfx::ScopedCanvas scoped_canvas(stroke_canvas); |
- const float scale = stroke_canvas->UndoDeviceScaleFactor(); |
- |
- gfx::Path stroke = GetBorderPath(scale, false, false, rect.size()); |
- Op(stroke, fill, kDifference_SkPathOp, &stroke); |
- if (!params.is_active) { |
- // Clip out the bottom line; this will be drawn for us by |
- // TabStrip::PaintChildren(). |
- stroke_canvas->ClipRect(gfx::RectF(rect.width() * scale, |
- rect.height() * scale - 1)); |
+ if (params.draw_hover) { |
+ DrawHighlight(canvas, params.hover_location * scale, radius * scale, |
+ hover_color); |
} |
- paint.setColor(params.stroke_color); |
- stroke_canvas->DrawPath(stroke, paint); |
} |
} else { |
- gfx::Canvas* canvas = stroke_canvas; |
- if (draw_hover) { |
+ if (params.draw_hover) { |
// Draw everything to a temporary canvas so we can extract an image for |
// use in masking the hover glow. |
gfx::Canvas background_canvas(rect.size(), canvas->image_scale(), false); |
@@ -562,7 +603,7 @@ void PaintTabBackgroundUsingParams(gfx::Canvas* fill_canvas, |
canvas->DrawImageInt(background_image, 0, 0); |
gfx::Canvas hover_canvas(rect.size(), canvas->image_scale(), false); |
- DrawHighlight(&hover_canvas, hover_location, radius, hover_color); |
+ DrawHighlight(&hover_canvas, params.hover_location, radius, hover_color); |
gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage( |
gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image); |
canvas->DrawImageInt(result, 0, 0); |
@@ -583,6 +624,27 @@ void PaintTabBackgroundUsingParams(gfx::Canvas* fill_canvas, |
} |
} |
+void PaintTabStrokeUsingParams(gfx::Canvas* canvas, |
+ const PaintBackgroundParams& params) { |
+ DCHECK(ui::MaterialDesignController::IsModeMaterial()); |
+ gfx::ScopedCanvas scoped_canvas(canvas); |
+ const float scale = canvas->UndoDeviceScaleFactor(); |
+ |
+ SkPaint paint; |
+ paint.setAntiAlias(true); |
+ gfx::Path stroke = GetBorderPath(scale, false, false, params.rect.size()); |
+ gfx::Path fill = GetFillPath(scale, params.rect.size()); |
+ Op(stroke, fill, kDifference_SkPathOp, &stroke); |
+ if (!params.is_active) { |
+ // Clip out the bottom line; this will be drawn for us by |
+ // TabStrip::PaintChildren(). |
+ canvas->ClipRect(gfx::RectF(params.rect.width() * scale, |
+ params.rect.height() * scale - 1)); |
+ } |
+ paint.setColor(params.stroke_color); |
+ canvas->DrawPath(stroke, paint); |
+} |
+ |
// Desaturates the favicon. Should only be used for when a tab encounters a |
// network error state. |
void PaintDesaturatedFavIcon(gfx::Canvas* canvas, |
@@ -1452,7 +1514,7 @@ void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) { |
GetThemeProvider()->HasCustomImage(kActiveTabFillId); |
const int y_offset = -GetYInsetForActiveTabBackground(); |
if (IsActive()) { |
- PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, |
+ PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, |
has_custom_image, y_offset); |
} else { |
PaintInactiveTabBackground(canvas, clip); |
@@ -1461,7 +1523,7 @@ 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, |
+ PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, |
has_custom_image, y_offset); |
canvas->Restore(); |
} |
@@ -1532,8 +1594,8 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, |
// 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 || hover_controller_.ShouldDraw()) { |
- PaintTabBackgroundUsingFillId(canvas, canvas, false, fill_id, |
- has_custom_image, y_offset); |
+ PaintTabBackgroundUsingFillId(canvas, false, fill_id, has_custom_image, |
+ y_offset); |
return; |
} |
@@ -1548,26 +1610,12 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, |
const ImageCacheEntryMetadata metadata( |
fill_id, tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), |
controller_->GetToolbarTopSeparatorColor(), use_fill_and_stroke_images, |
- ui::GetSupportedScaleFactor(canvas->image_scale()), size()); |
+ 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, |
- fill_id, false, y_offset); |
- g_image_cache->emplace_front( |
- metadata, gfx::ImageSkia(tmp_fill_canvas.ExtractImageRep()), |
- gfx::ImageSkia(tmp_canvas.ExtractImageRep())); |
- } else { |
- PaintTabBackgroundUsingFillId(&tmp_canvas, &tmp_canvas, false, fill_id, |
- false, y_offset); |
- g_image_cache->emplace_front( |
- metadata, gfx::ImageSkia(), |
- gfx::ImageSkia(tmp_canvas.ExtractImageRep())); |
- } |
+ g_image_cache->emplace_front(metadata, this, fill_id, y_offset); |
if (g_image_cache->size() > kMaxImageCacheSize) |
g_image_cache->pop_back(); |
it = g_image_cache->begin(); |
@@ -1582,14 +1630,11 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, |
canvas->DrawImageInt(it->stroke_image, 0, 0); |
} |
-void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas, |
- gfx::Canvas* stroke_canvas, |
+void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* canvas, |
bool is_active, |
int fill_id, |
bool has_custom_image, |
int y_offset) { |
- views::GlowHoverController* hc = |
- hover_controller_.ShouldDraw() ? &hover_controller_ : nullptr; |
gfx::ImageSkia* fill_image = |
has_custom_image || !ui::MaterialDesignController::IsModeMaterial() |
? GetThemeProvider()->GetImageSkiaNamed(fill_id) |
@@ -1603,9 +1648,12 @@ void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas, |
is_active, fill_image, has_custom_image, rect, |
controller_->GetToolbarTopSeparatorColor(), |
GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR), |
- GetThemeProvider()->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB)); |
+ GetThemeProvider()->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), |
+ !is_active && hover_controller_.ShouldDraw(), |
+ hover_controller_.location(), hover_controller_.GetAlpha()); |
- PaintTabBackgroundUsingParams(fill_canvas, stroke_canvas, hc, params); |
+ PaintTabFillUsingParams(canvas, params); |
+ PaintTabStrokeUsingParams(canvas, params); |
} |
void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon( |