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

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

Issue 1401633003: Implement Material Design for the tabstrip. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Resync Created 5 years 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') | chrome/browser/ui/views/tabs/tab_strip.cc » ('j') | 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 f4fcad526683015f82d81f4f68578675cd0695f4..87250a99a5f6823cbc614d8db28bf3abeb6b1678 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -26,9 +26,11 @@
#include "grit/components_scaled_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "third_party/skia/include/pathops/SkPathOps.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/list_selection_model.h"
+#include "ui/base/resource/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/animation/animation_container.h"
@@ -41,6 +43,7 @@
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/path.h"
+#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vector_icons_public.h"
#include "ui/resources/grit/ui_resources.h"
@@ -436,6 +439,7 @@ Tab::ImageCacheEntry::~ImageCacheEntry() {}
// static
const char Tab::kViewClassName[] = "Tab";
+const SkColor Tab::kInactiveTabColor = SkColorSetRGB(0xD0, 0xD0, 0xD0);
Tab::TabImages Tab::active_images_ = {0};
Tab::TabImages Tab::inactive_images_ = {0};
Tab::TabImages Tab::mask_images_ = {0};
@@ -648,10 +652,17 @@ int Tab::GetWidthOfLargestSelectableRegion() const {
}
gfx::Size Tab::GetMinimumInactiveSize() {
- // Since we use images, the real minimum height of the image is
- // defined most accurately by the height of the end cap images.
- InitTabResources();
- int height = active_images_.image_l->height();
+ int height;
+ if (ui::MaterialDesignController::IsModeMaterial()) {
+ const int kTabHeight = 29;
+ height = kTabHeight;
+ } else {
+ // Since we use images, the real minimum height of the image is
+ // defined most accurately by the height of the end cap images.
+ InitTabResources();
+ height = active_images_.image_l->height();
+ }
+
return gfx::Size(GetLayoutInsets(TAB).width(), height);
}
@@ -765,51 +776,58 @@ bool Tab::GetHitTestMask(gfx::Path* mask) const {
const bool extend_to_top =
widget && (widget->IsMaximized() || widget->IsFullscreen());
- // Hit mask constants.
- const SkScalar kTabCapWidth = 15;
- const SkScalar kTabTopCurveWidth = 4;
- const SkScalar kTabBottomCurveWidth = 3;
+ if (ui::MaterialDesignController::IsModeMaterial()) {
+ SkPath border;
+ const float scale = GetWidget()->GetCompositor()->device_scale_factor();
+ GetBorderPath(scale, extend_to_top, &border);
+ mask->addPath(border, SkMatrix::MakeScale(1 / scale));
+ } else {
+ // Hit mask constants.
+ const SkScalar kTabCapWidth = 15;
+ const SkScalar kTabTopCurveWidth = 4;
+ const SkScalar kTabBottomCurveWidth = 3;
#if defined(OS_MACOSX)
- // Mac's Cocoa UI doesn't have shadows.
- const SkScalar kTabInset = 0;
+ // Mac's Cocoa UI doesn't have shadows.
+ const SkScalar kTabInset = 0;
#elif defined(TOOLKIT_VIEWS)
- // The views browser UI has shadows in the left, right and top parts of the
- // tab.
- const SkScalar kTabInset = 6;
+ // The views browser UI has shadows in the left, right and top parts of the
+ // tab.
+ const SkScalar kTabInset = 6;
#endif
- SkScalar left = kTabInset;
- SkScalar top = GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT);
- SkScalar right = SkIntToScalar(width()) - kTabInset;
- SkScalar bottom = SkIntToScalar(height());
+ SkScalar left = kTabInset;
+ SkScalar top = GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT);
+ SkScalar right = SkIntToScalar(width()) - kTabInset;
+ SkScalar bottom = SkIntToScalar(height());
- // Start in the lower-left corner.
- mask->moveTo(left, bottom);
+ // Start in the lower-left corner.
+ mask->moveTo(left, bottom);
- // Left end cap.
- mask->lineTo(left + kTabBottomCurveWidth, bottom - kTabBottomCurveWidth);
- mask->lineTo(left + kTabCapWidth - kTabTopCurveWidth,
- top + kTabTopCurveWidth);
- mask->lineTo(left + kTabCapWidth, top);
+ // Left end cap.
+ mask->lineTo(left + kTabBottomCurveWidth, bottom - kTabBottomCurveWidth);
+ mask->lineTo(left + kTabCapWidth - kTabTopCurveWidth,
+ top + kTabTopCurveWidth);
+ mask->lineTo(left + kTabCapWidth, top);
- // Extend over the top shadow area if we have one and the caller wants it.
- if (top > 0 && extend_to_top) {
- mask->lineTo(left + kTabCapWidth, 0);
- mask->lineTo(right - kTabCapWidth, 0);
- }
+ // Extend over the top shadow area if we have one and the caller wants it.
+ if (top > 0 && extend_to_top) {
+ mask->lineTo(left + kTabCapWidth, 0);
+ mask->lineTo(right - kTabCapWidth, 0);
+ }
- // Connect to the right cap.
- mask->lineTo(right - kTabCapWidth, top);
+ // Connect to the right cap.
+ mask->lineTo(right - kTabCapWidth, top);
- // Right end cap.
- mask->lineTo(right - kTabCapWidth + kTabTopCurveWidth,
- top + kTabTopCurveWidth);
- mask->lineTo(right - kTabBottomCurveWidth, bottom - kTabBottomCurveWidth);
- mask->lineTo(right, bottom);
+ // Right end cap.
+ mask->lineTo(right - kTabCapWidth + kTabTopCurveWidth,
+ top + kTabTopCurveWidth);
+ mask->lineTo(right - kTabBottomCurveWidth, bottom - kTabBottomCurveWidth);
+ mask->lineTo(right, bottom);
- // Close out the path.
- mask->lineTo(left, bottom);
- mask->close();
+ // Close out the path.
+ mask->lineTo(left, bottom);
+ mask->close();
+ }
// It is possible for a portion of the tab to be occluded if tabs are
// stacked, so modify the hit test mask to only include the visible
@@ -1240,15 +1258,26 @@ void Tab::PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas) {
}
SkPoint p;
p.set(SkDoubleToScalar(x), 0);
- gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
- PaintInactiveTabBackground(&background_canvas);
- gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
- canvas->DrawImageInt(background_image, 0, 0);
- gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
- DrawHighlight(&hover_canvas, p, SkFloatToScalar(radius), alpha);
- gfx::ImageSkia hover_image = gfx::ImageSkiaOperations::CreateMaskedImage(
- gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
- canvas->DrawImageInt(hover_image, 0, 0);
+ if (ui::MaterialDesignController::IsModeMaterial()) {
+ PaintInactiveTabBackground(canvas);
+ gfx::ScopedCanvas scoped_canvas(canvas);
+ const float scale = canvas->UndoDeviceScaleFactor();
+ SkPath fill;
+ GetFillPath(scale, &fill);
+ canvas->ClipPath(fill, true);
+ p.scale(SkFloatToScalar(scale));
+ DrawHighlight(canvas, p, SkFloatToScalar(radius * scale), alpha);
+ } else {
+ gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
+ PaintInactiveTabBackground(&background_canvas);
+ gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
+ canvas->DrawImageInt(background_image, 0, 0);
+ gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
+ DrawHighlight(&hover_canvas, p, SkFloatToScalar(radius), alpha);
+ gfx::ImageSkia hover_image = gfx::ImageSkiaOperations::CreateMaskedImage(
+ gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
+ canvas->DrawImageInt(hover_image, 0, 0);
+ }
}
void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) {
@@ -1303,31 +1332,75 @@ void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* canvas,
SkPoint hover_location(PointToSkPoint(hover_controller_.location()));
const SkAlpha hover_alpha = hover_controller_.GetAlpha();
- if (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(size(), canvas->image_scale(), false);
- PaintTabFill(&background_canvas, fill_image, x_offset, y_offset, is_active);
- gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
- canvas->DrawImageInt(background_image, 0, 0);
+ if (ui::MaterialDesignController::IsModeMaterial()) {
+ gfx::ScopedCanvas scoped_canvas(canvas);
+ const float scale = canvas->UndoDeviceScaleFactor();
+
+ // Draw the fill.
+ SkPath fill;
+ GetFillPath(scale, &fill);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ {
+ gfx::ScopedCanvas clip_scoper(canvas);
+ canvas->ClipPath(fill, true);
+ if (has_custom_image) {
+ gfx::ScopedCanvas scale_scoper(canvas);
+ canvas->sk_canvas()->scale(scale, scale);
+ canvas->TileImageInt(*fill_image, x_offset, y_offset, 0, 0, width(),
+ height());
+ } else {
+ paint.setColor(
+ is_active ? SkColorSetRGB(0xF2, 0xF2, 0xF2) : kInactiveTabColor);
+ canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale),
+ paint);
+ }
+ if (draw_hover) {
+ hover_location.scale(SkFloatToScalar(scale));
+ DrawHighlight(canvas, hover_location, radius * scale, hover_alpha);
+ }
+ }
- gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
- DrawHighlight(&hover_canvas, hover_location, radius, hover_alpha);
- gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage(
- gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
- canvas->DrawImageInt(result, 0, 0);
+ // Draw the stroke.
+ SkPath stroke;
+ GetBorderPath(scale, false, &stroke);
+ Op(stroke, fill, kDifference_SkPathOp, &stroke);
+ if (!is_active) {
+ // Clip out the bottom line; this will be drawn for us by
+ // TabStrip::PaintChildren().
+ canvas->sk_canvas()->clipRect(
+ SkRect::MakeWH(width() * scale, height() * scale - 1));
+ }
+ paint.setARGB(0x40, 0x00, 0x00, 0x00);
+ canvas->DrawPath(stroke, paint);
} else {
- PaintTabFill(canvas, fill_image, x_offset, y_offset, is_active);
- }
+ if (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(size(), canvas->image_scale(), false);
+ PaintTabFill(&background_canvas, fill_image, x_offset, y_offset,
+ is_active);
+ gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
+ canvas->DrawImageInt(background_image, 0, 0);
+
+ gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
+ DrawHighlight(&hover_canvas, hover_location, radius, hover_alpha);
+ gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage(
+ gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
+ canvas->DrawImageInt(result, 0, 0);
+ } else {
+ PaintTabFill(canvas, fill_image, x_offset, y_offset, is_active);
+ }
- // Now draw the stroke, highlights, and shadows around the tab edge.
- TabImages* stroke_images = is_active ? &active_images_ : &inactive_images_;
- canvas->DrawImageInt(*stroke_images->image_l, 0, 0);
- canvas->TileImageInt(
- *stroke_images->image_c, stroke_images->l_width, 0,
- width() - stroke_images->l_width - stroke_images->r_width, height());
- canvas->DrawImageInt(*stroke_images->image_r,
- width() - stroke_images->r_width, 0);
+ // Now draw the stroke, highlights, and shadows around the tab edge.
+ TabImages* stroke_images = is_active ? &active_images_ : &inactive_images_;
+ canvas->DrawImageInt(*stroke_images->image_l, 0, 0);
+ canvas->TileImageInt(
+ *stroke_images->image_c, stroke_images->l_width, 0,
+ width() - stroke_images->l_width - stroke_images->r_width, height());
+ canvas->DrawImageInt(*stroke_images->image_r,
+ width() - stroke_images->r_width, 0);
+ }
}
void Tab::PaintTabFill(gfx::Canvas* canvas,
@@ -1543,6 +1616,66 @@ void Tab::ScheduleIconPaint() {
SchedulePaintInRect(bounds);
}
+void Tab::GetFillPath(float scale, SkPath* fill) const {
+ const float right = width() * scale;
+ const float bottom = height() * scale;
+
+ fill->moveTo(right - 1, bottom);
+ fill->rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale,
+ -1.5 * scale);
+ fill->lineTo(right - 1 - 13.5 * scale, 2.5 * scale);
+ // Prevent overdraw in the center near minimum width (only happens if
+ // scale < 2). We could instead avoid this by increasing the tab inset
+ // values, but that would shift all the content inward as well, unless we
+ // then overlapped the content on the endcaps, by which point we'd have a
+ // huge mess.
+ const float total_endcap_width = 31 * scale + 2;
+ const float overlap = total_endcap_width - right;
+ const float offset = (overlap > 0) ? (overlap / 2) : 0;
+ fill->rCubicTo(-0.375 * scale, -1 * scale, -1.25 * scale + offset,
+ -1.5 * scale, -2 * scale + offset, -1.5 * scale);
+ if (overlap < 0)
+ fill->lineTo(1 + 15.5 * scale, scale);
+ fill->rCubicTo(-0.75 * scale, 0, -1.625 * scale - offset, 0.5 * scale,
+ -2 * scale - offset, 1.5 * scale);
+ fill->lineTo(1 + 2 * scale, bottom - 1.5 * scale);
+ fill->rCubicTo(-0.375 * scale, scale, -1.25 * scale, 1.5 * scale, -2 * scale,
+ 1.5 * scale);
+ fill->close();
+}
+
+void Tab::GetBorderPath(float scale, bool extend_to_top, SkPath* path) const {
+ const float top = scale - 1;
+ const float right = width() * scale;
+ const float bottom = height() * scale;
+
+ path->moveTo(0, bottom);
+ path->rLineTo(0, -1);
+ path->rCubicTo(0.75 * scale, 0, 1.625 * scale, -0.5 * scale, 2 * scale,
+ -1.5 * scale);
+ path->lineTo(13.5 * scale, top + 1.5 * scale);
+ if (extend_to_top) {
+ // Create the vertical extension by extending the side diagonals until they
+ // reach the top of the bounds.
+ const float dy = 2.5 * scale - 1;
+ const float dx = 11.5 / 25 * dy;
+ path->rLineTo(dx, -dy);
+ path->lineTo(right - 13.5 * scale - dx, 0);
+ path->rLineTo(dx, dy);
+ } else {
+ path->rCubicTo(0.375 * scale, -scale, 1.25 * scale, -1.5 * scale, 2 * scale,
+ -1.5 * scale);
+ path->lineTo(right - 15.5 * scale, top);
+ path->rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale,
+ 1.5 * scale);
+ }
+ path->lineTo(right - 2 * scale, bottom - 1 - 1.5 * scale);
+ path->rCubicTo(0.375 * scale, scale, 1.25 * scale, 1.5 * scale, 2 * scale,
+ 1.5 * scale);
+ path->rLineTo(0, 1);
+ path->close();
+}
+
gfx::Rect Tab::GetImmersiveBarRect() const {
// The main bar is as wide as the normal tab's horizontal top line.
// This top line of the tab extends a few pixels left and right of the
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.h ('k') | chrome/browser/ui/views/tabs/tab_strip.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698