Commit 65181316 authored by Peter Kasting's avatar Peter Kasting Committed by Commit Bot

Cleanup pre-refresh functionality in tab.cc, part 1.

This removes support for pre-refresh modes.  It does not change the design of
path computations/drawing or other deeper refactors.

Also does some other minor cleanup, and fixes one clear bug with high DPI in
PaintChildren().

Bug: 873855
Change-Id: I3496ea60ed670d5f1c30abf33b989162c558fa16
Reviewed-on: https://chromium-review.googlesource.com/1231898Reviewed-by: default avatarAllen Bauer <kylixrd@chromium.org>
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#592527}
parent c1e2f785
...@@ -322,64 +322,12 @@ IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest, ...@@ -322,64 +322,12 @@ IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest,
manager->ShowWindowForUser(window, account_id2); manager->ShowWindowForUser(window, account_id2);
EXPECT_TRUE(MultiUserWindowManager::ShouldShowAvatar(window)); EXPECT_TRUE(MultiUserWindowManager::ShouldShowAvatar(window));
if (GetParam() != switches::kTopChromeMDMaterialRefresh) {
// An icon should show on the top left corner of the teleported browser
// window.
EXPECT_TRUE(frame_view->profile_indicator_icon());
}
// Teleport the window back to owner desktop. // Teleport the window back to owner desktop.
manager->ShowWindowForUser(window, account_id1); manager->ShowWindowForUser(window, account_id1);
EXPECT_FALSE(MultiUserWindowManager::ShouldShowAvatar(window)); EXPECT_FALSE(MultiUserWindowManager::ShouldShowAvatar(window));
EXPECT_FALSE(frame_view->profile_indicator_icon()); EXPECT_FALSE(frame_view->profile_indicator_icon());
} }
// Hit Test for Avatar Menu Button on ChromeOS.
IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest,
AvatarMenuButtonHitTestOnChromeOS) {
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
BrowserNonClientFrameViewAsh* frame_view = GetFrameViewAsh(browser_view);
gfx::Point avatar_center(profiles::kAvatarIconWidth / 2,
profiles::kAvatarIconHeight / 2);
// The increased header height in the touch-optimized UI affects the expected
// result.
int expected_value =
GetParam() == switches::kTopChromeMDMaterialTouchOptimized ? HTCAPTION
: HTCLIENT;
EXPECT_EQ(expected_value, frame_view->NonClientHitTest(avatar_center));
EXPECT_FALSE(frame_view->profile_indicator_icon());
const AccountId current_user =
multi_user_util::GetAccountIdFromProfile(browser()->profile());
TestMultiUserWindowManager* manager =
new TestMultiUserWindowManager(browser(), current_user);
// Teleport the window to another desktop.
const AccountId account_id2(AccountId::FromUserEmail("user2"));
manager->ShowWindowForUser(browser()->window()->GetNativeWindow(),
account_id2);
if (GetParam() != switches::kTopChromeMDMaterialRefresh) {
// Clicking on the avatar icon should have same behaviour like clicking on
// the caption area, i.e., allow the user to drag the browser window around.
EXPECT_EQ(HTCAPTION, frame_view->NonClientHitTest(avatar_center));
EXPECT_TRUE(frame_view->profile_indicator_icon());
}
}
// Tests that for an incognito browser, there is an avatar icon view, unless in
// touch-optimized mode.
IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest, IncognitoAvatar) {
Browser* incognito_browser = CreateIncognitoBrowser();
BrowserView* browser_view =
BrowserView::GetBrowserViewForBrowser(incognito_browser);
BrowserNonClientFrameViewAsh* frame_view = GetFrameViewAsh(browser_view);
const bool should_have_avatar = GetParam() == switches::kTopChromeMDMaterial;
const bool has_avatar = !!frame_view->profile_indicator_icon();
EXPECT_EQ(should_have_avatar, has_avatar);
}
IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest, IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest,
IncognitoMarkedAsAssistantBlocked) { IncognitoMarkedAsAssistantBlocked) {
Browser* incognito_browser = CreateIncognitoBrowser(); Browser* incognito_browser = CreateIncognitoBrowser();
...@@ -1448,12 +1396,11 @@ IN_PROC_BROWSER_TEST_P(NonHomeLauncherBrowserNonClientFrameViewAshTest, ...@@ -1448,12 +1396,11 @@ IN_PROC_BROWSER_TEST_P(NonHomeLauncherBrowserNonClientFrameViewAshTest,
EXPECT_EQ(expected_height, frame_view->frame_header_->GetHeaderHeight()); EXPECT_EQ(expected_height, frame_view->frame_header_->GetHeaderHeight());
} }
#define INSTANTIATE_TEST_CASE(name) \ #define INSTANTIATE_TEST_CASE(name) \
INSTANTIATE_TEST_CASE_P( \ INSTANTIATE_TEST_CASE_P( \
, name, \ , name, \
::testing::Values(switches::kTopChromeMDMaterial, \ ::testing::Values(switches::kTopChromeMDMaterialRefresh, \
switches::kTopChromeMDMaterialTouchOptimized, \ switches::kTopChromeMDMaterialRefreshTouchOptimized), \
switches::kTopChromeMDMaterialRefresh), \
&TopChromeMdParamToString) &TopChromeMdParamToString)
INSTANTIATE_TEST_CASE(BrowserNonClientFrameViewAshTest); INSTANTIATE_TEST_CASE(BrowserNonClientFrameViewAshTest);
......
...@@ -78,12 +78,6 @@ using MD = ui::MaterialDesignController; ...@@ -78,12 +78,6 @@ using MD = ui::MaterialDesignController;
namespace { namespace {
constexpr int kExtraLeftPaddingToBalanceCloseButtonPadding = 2;
constexpr int kRefreshExtraLeftPaddingToBalanceCloseButtonPadding = 4;
constexpr int kRefreshAlertIndicatorCloseButtonPadding = 6;
constexpr int kTouchableRefreshAlertIndicatorCloseButtonPadding = 8;
// When a non-pinned tab becomes a pinned tab the width of the tab animates. If // When a non-pinned tab becomes a pinned tab the width of the tab animates. If
// the width of a pinned tab is at least kPinnedTabExtraWidthToRenderAsNormal // the width of a pinned tab is at least kPinnedTabExtraWidthToRenderAsNormal
// larger than the desired pinned tab width then the tab is rendered as a normal // larger than the desired pinned tab width then the tab is rendered as a normal
...@@ -94,14 +88,6 @@ constexpr int kPinnedTabExtraWidthToRenderAsNormal = 30; ...@@ -94,14 +88,6 @@ constexpr int kPinnedTabExtraWidthToRenderAsNormal = 30;
// Opacity of the active tab background painted over inactive selected tabs. // Opacity of the active tab background painted over inactive selected tabs.
constexpr float kSelectedTabOpacity = 0.75f; constexpr float kSelectedTabOpacity = 0.75f;
// Inactive selected tabs have their throb value scaled by this.
constexpr float kSelectedTabThrobScale = 0.95f - kSelectedTabOpacity;
// Height of the separator painted on the left edge of the tab for the material
// refresh mode.
constexpr int kTabSeparatorHeight = 20;
constexpr int kTabSeparatorTouchHeight = 24;
// Helper functions ------------------------------------------------------------ // Helper functions ------------------------------------------------------------
// Returns the coordinate for an object of size |item_size| centered in a region // Returns the coordinate for an object of size |item_size| centered in a region
...@@ -119,27 +105,6 @@ int Center(int size, int item_size) { ...@@ -119,27 +105,6 @@ int Center(int size, int item_size) {
return extra_space / 2; return extra_space / 2;
} }
// For non-material-refresh mode, returns the width of the tab endcap in DIP.
// More precisely, this is the width of the curve making up either the outer or
// inner edge of the stroke.
//
// These two curves are horizontally offset by 1 px (regardless of scale); the
// total width of the endcap from tab outer edge to the inside end of the stroke
// inner edge is (GetTabEndcapWidthForLayout() * scale) + 1.
int GetTabEndcapWidthForLayout() {
const int mode = MD::GetMode();
DCHECK_LE(mode, 2);
constexpr int kEndcapWidth[] = {16, 18, 24};
return kEndcapWidth[mode];
}
// For painting the endcaps, the top corners are actually shifted outwards 0.5
// DIP from the grid.
float GetTabEndcapWidthForPainting() {
return GetTabEndcapWidthForLayout() - 0.5f;
}
void DrawHighlight(gfx::Canvas* canvas, void DrawHighlight(gfx::Canvas* canvas,
const SkPoint& p, const SkPoint& p,
SkScalar radius, SkScalar radius,
...@@ -217,12 +182,15 @@ float GetTopCornerRadiusForWidth(int width) { ...@@ -217,12 +182,15 @@ float GetTopCornerRadiusForWidth(int width) {
return base::ClampToRange<float>(radius, 0, ideal_radius); return base::ClampToRange<float>(radius, 0, ideal_radius);
} }
// The refresh-specific implementation of GetInteriorPath() (see below). // Returns a path corresponding to the tab's content region inside the outer
gfx::Path GetRefreshInteriorPath(float scale, // stroke. The sides of the path will be inset by |insets|; this is useful when
float stroke_thickness, // trying to clip favicons to match the overall tab shape but be inset from the
float bottom_offset, // edge.
const gfx::Rect& bounds, gfx::Path GetInteriorPath(float scale,
const gfx::InsetsF& insets) { float stroke_thickness,
float bottom_offset,
const gfx::Rect& bounds,
const gfx::InsetsF& insets = gfx::InsetsF()) {
const gfx::RectF aligned_bounds = const gfx::RectF aligned_bounds =
ScaleAndAlignBounds(bounds, scale, stroke_thickness); ScaleAndAlignBounds(bounds, scale, stroke_thickness);
...@@ -304,61 +272,18 @@ gfx::Path GetRefreshInteriorPath(float scale, ...@@ -304,61 +272,18 @@ gfx::Path GetRefreshInteriorPath(float scale,
return OffsetAndIntersectPaths(left_path, right_path, insets.Scale(scale)); return OffsetAndIntersectPaths(left_path, right_path, insets.Scale(scale));
} }
// Returns a path corresponding to the tab's content region inside the outer // Returns a path corresponding to the tab's outer border for a given tab
// stroke. The sides of the path will be inset by |insets|; this is useful when // |scale| and |bounds|. If |unscale_at_end| is true, this path will be
// trying to clip favicons to match the overall tab shape but be inset from the // normalized to a 1x scale by scaling by 1/scale before returning. If
// edge. // |extend_to_top| is true, the path is extended vertically to the top of the
gfx::Path GetInteriorPath(float scale, // tab bounds. The caller uses this for Fitts' Law purposes in
float stroke_thickness, // maximized/fullscreen mode.
float bottom_offset, gfx::Path GetBorderPath(float scale,
const gfx::Rect& bounds, float stroke_thickness,
const gfx::InsetsF& insets = gfx::InsetsF()) { float bottom_offset,
if (MD::IsRefreshUi()) bool unscale_at_end,
return GetRefreshInteriorPath(scale, stroke_thickness, bottom_offset, bool extend_to_top,
bounds, insets); const gfx::Rect& bounds) {
const float right = bounds.width() * scale;
// The bottom of the tab needs to be pixel-aligned or else when we call
// ClipPath with anti-aliasing enabled it can cause artifacts.
const float bottom = std::ceil(bounds.height() * scale);
const float endcap_width = GetTabEndcapWidthForPainting();
// Construct the interior path by intersecting paths representing the left
// and right halves of the tab. Compared to computing the full path at once,
// this makes it easier to avoid overdraw in the top center near minimum
// width, and to implement cases where !insets.IsEmpty().
gfx::Path right_path;
right_path.moveTo(right - 1, bottom);
right_path.rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale,
-2 * scale, -1.5 * scale);
right_path.lineTo(right - 1 - (endcap_width - 2) * scale, 2.5 * scale);
right_path.rCubicTo(-0.375 * scale, -1 * scale, -1.25 * scale, -1.5 * scale,
-2 * scale, -1.5 * scale);
right_path.lineTo(0, scale);
right_path.lineTo(0, bottom);
right_path.close();
gfx::Path left_path;
left_path.moveTo(1 + endcap_width * scale, scale);
left_path.rCubicTo(-0.75 * scale, 0, -1.625 * scale, 0.5 * scale, -2 * scale,
1.5 * scale);
left_path.lineTo(1 + 2 * scale, bottom - 1.5 * scale);
left_path.rCubicTo(-0.375 * scale, scale, -1.25 * scale, 1.5 * scale,
-2 * scale, 1.5 * scale);
left_path.lineTo(right, bottom);
left_path.lineTo(right, scale);
left_path.close();
return OffsetAndIntersectPaths(left_path, right_path, insets.Scale(scale));
}
// The refresh-specific implementation of GetBorderPath() (see below).
gfx::Path GetRefreshBorderPath(const gfx::Rect& bounds,
bool extend_to_top,
float scale,
float stroke_thickness,
float bottom_offset) {
const gfx::RectF aligned_bounds = const gfx::RectF aligned_bounds =
ScaleAndAlignBounds(bounds, scale, stroke_thickness); ScaleAndAlignBounds(bounds, scale, stroke_thickness);
...@@ -369,7 +294,7 @@ gfx::Path GetRefreshBorderPath(const gfx::Rect& bounds, ...@@ -369,7 +294,7 @@ gfx::Path GetRefreshBorderPath(const gfx::Rect& bounds,
const float bottom_radius = const float bottom_radius =
std::max(top_radius - stroke_thickness, 0.f) - bottom_offset; std::max(top_radius - stroke_thickness, 0.f) - bottom_offset;
// See comments in GetRefreshInteriorPath(). // See comments in GetInteriorPath().
const float extension = Tab::GetCornerRadius() * scale; const float extension = Tab::GetCornerRadius() * scale;
const float corner_gap = extension - bottom_radius; const float corner_gap = extension - bottom_radius;
...@@ -432,83 +357,6 @@ gfx::Path GetRefreshBorderPath(const gfx::Rect& bounds, ...@@ -432,83 +357,6 @@ gfx::Path GetRefreshBorderPath(const gfx::Rect& bounds,
origin.Scale(scale); origin.Scale(scale);
path.offset(-origin.x(), -origin.y()); path.offset(-origin.x(), -origin.y());
return path;
}
// Returns the inverse of the slope of the diagonal portion of the tab outer
// border. (This is a positive value, so it's specifically for the slope of the
// leading edge.)
//
// This returns the inverse (dx/dy instead of dy/dx) because we use exact values
// for the vertical distances between points and then compute the horizontal
// deltas from those.
float GetInverseDiagonalSlope() {
// In refresh, tab sides do not have slopes, so no one should call this.
DCHECK(!MD::IsRefreshUi());
// This is computed from the border path as follows:
// * The endcap width is enough for the whole stroke outer curve, i.e. the
// side diagonal plus the curves on both its ends.
// * The bottom and top curve together are 4 DIP wide, so the diagonal is
// (endcap width - 4) DIP wide.
// * The bottom and top curve are each 1.5 px high. Additionally, there is an
// extra 1 px below the bottom curve and (scale - 1) px above the top curve,
// so the diagonal is ((height - 1.5 - 1.5) * scale - 1 - (scale - 1)) px
// high. Simplifying this gives (height - 4) * scale px, or (height - 4)
// DIP.
return (GetTabEndcapWidthForPainting() - 4) /
(GetLayoutConstant(TAB_HEIGHT) - 4);
}
// Returns a path corresponding to the tab's outer border for a given tab
// |scale| and |bounds|. If |unscale_at_end| is true, this path will be
// normalized to a 1x scale by scaling by 1/scale before returning. If
// |extend_to_top| is true, the path is extended vertically to the top of the
// tab bounds. The caller uses this for Fitts' Law purposes in
// maximized/fullscreen mode.
gfx::Path GetBorderPath(float scale,
float stroke_thickness,
float bottom_offset,
bool unscale_at_end,
bool extend_to_top,
const gfx::Rect& bounds) {
gfx::Path path;
if (MD::IsRefreshUi()) {
path = GetRefreshBorderPath(bounds, extend_to_top, scale, stroke_thickness,
bottom_offset);
} else {
const float top = scale - stroke_thickness;
const float right = bounds.width() * scale;
const float bottom = bounds.height() * scale;
const float endcap_width = GetTabEndcapWidthForPainting();
path.moveTo(0, bottom);
path.rLineTo(0, -stroke_thickness);
path.rCubicTo(0.75 * scale, 0, 1.625 * scale, -0.5 * scale, 2 * scale,
-1.5 * scale);
path.lineTo((endcap_width - 2) * 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 - stroke_thickness;
const float dx = GetInverseDiagonalSlope() * dy;
path.rLineTo(dx, -dy);
path.lineTo(right - (endcap_width - 2) * 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 - endcap_width * 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 - stroke_thickness - 1.5 * scale);
path.rCubicTo(0.375 * scale, scale, 1.25 * scale, 1.5 * scale, 2 * scale,
1.5 * scale);
path.rLineTo(0, stroke_thickness);
path.close();
}
if (unscale_at_end && (scale != 1)) if (unscale_at_end && (scale != 1))
path.transform(SkMatrix::MakeScale(1.f / scale)); path.transform(SkMatrix::MakeScale(1.f / scale));
...@@ -640,7 +488,7 @@ bool Tab::GetHitTestMask(gfx::Path* mask) const { ...@@ -640,7 +488,7 @@ bool Tab::GetHitTestMask(gfx::Path* mask) const {
const views::Widget* widget = GetWidget(); const views::Widget* widget = GetWidget();
*mask = GetBorderPath( *mask = GetBorderPath(
GetWidget()->GetCompositor()->device_scale_factor(), GetStrokeThickness(), GetWidget()->GetCompositor()->device_scale_factor(), GetStrokeThickness(),
IsActive() ? 0 : controller_->GetStrokeThickness(), true, GetBottomStrokeThickness(), true,
widget && (widget->IsMaximized() || widget->IsFullscreen()), bounds()); widget && (widget->IsMaximized() || widget->IsFullscreen()), bounds());
return true; return true;
} }
...@@ -651,15 +499,12 @@ void Tab::Layout() { ...@@ -651,15 +499,12 @@ void Tab::Layout() {
const bool was_showing_icon = showing_icon_; const bool was_showing_icon = showing_icon_;
UpdateIconVisibility(); UpdateIconVisibility();
int extra_left_padding = 0; int start = contents_rect.x();
if (extra_padding_before_content_) { if (extra_padding_before_content_) {
extra_left_padding = constexpr int kExtraLeftPaddingToBalanceCloseButtonPadding = 4;
MD::IsRefreshUi() ? kRefreshExtraLeftPaddingToBalanceCloseButtonPadding start += kExtraLeftPaddingToBalanceCloseButtonPadding;
: kExtraLeftPaddingToBalanceCloseButtonPadding;
} }
const int start = contents_rect.x() + extra_left_padding;
// The bounds for the favicon will include extra width for the attention // The bounds for the favicon will include extra width for the attention
// indicator, but visually it will be smaller at kFaviconSize wide. // indicator, but visually it will be smaller at kFaviconSize wide.
gfx::Rect favicon_bounds(start, contents_rect.y(), 0, 0); gfx::Rect favicon_bounds(start, contents_rect.y(), 0, 0);
...@@ -723,18 +568,18 @@ void Tab::Layout() { ...@@ -723,18 +568,18 @@ void Tab::Layout() {
close_button_->SetVisible(showing_close_button_); close_button_->SetVisible(showing_close_button_);
if (showing_alert_indicator_) { if (showing_alert_indicator_) {
const bool is_touch_optimized = MD::IsTouchOptimizedUiEnabled(); int right = contents_rect.right();
const gfx::Size image_size(alert_indicator_button_->GetPreferredSize()); if (showing_close_button_) {
int alert_to_close_spacing = 0; right = close_x;
if (extra_alert_indicator_padding_) { if (extra_alert_indicator_padding_) {
alert_to_close_spacing = constexpr int kTouchableAlertIndicatorCloseButtonPadding = 8;
is_touch_optimized ? kTouchableRefreshAlertIndicatorCloseButtonPadding constexpr int kAlertIndicatorCloseButtonPadding = 6;
: kRefreshAlertIndicatorCloseButtonPadding; right -= MD::IsTouchOptimizedUiEnabled()
} else if (!MD::IsRefreshUi() && is_touch_optimized) { ? kTouchableAlertIndicatorCloseButtonPadding
alert_to_close_spacing = after_title_padding; : kAlertIndicatorCloseButtonPadding;
}
} }
const int right = showing_close_button_ ? (close_x - alert_to_close_spacing) const gfx::Size image_size = alert_indicator_button_->GetPreferredSize();
: contents_rect.right();
gfx::Rect bounds( gfx::Rect bounds(
std::max(contents_rect.x(), right - image_size.width()), std::max(contents_rect.x(), right - image_size.width()),
contents_rect.y() + Center(contents_rect.height(), image_size.height()), contents_rect.y() + Center(contents_rect.height(), image_size.height()),
...@@ -900,14 +745,14 @@ void Tab::OnMouseEntered(const ui::MouseEvent& event) { ...@@ -900,14 +745,14 @@ void Tab::OnMouseEntered(const ui::MouseEvent& event) {
hover_controller_.SetSubtleOpacityScale( hover_controller_.SetSubtleOpacityScale(
controller_->GetHoverOpacityForRadialHighlight()); controller_->GetHoverOpacityForRadialHighlight());
hover_controller_.Show(GlowHoverController::SUBTLE); hover_controller_.Show(GlowHoverController::SUBTLE);
OnButtonColorMaybeChanged(); UpdateForegroundColors();
Layout(); Layout();
} }
void Tab::OnMouseExited(const ui::MouseEvent& event) { void Tab::OnMouseExited(const ui::MouseEvent& event) {
mouse_hovered_ = false; mouse_hovered_ = false;
hover_controller_.Hide(); hover_controller_.Hide();
OnButtonColorMaybeChanged(); UpdateForegroundColors();
Layout(); Layout();
} }
...@@ -987,24 +832,19 @@ void Tab::PaintChildren(const views::PaintInfo& info) { ...@@ -987,24 +832,19 @@ void Tab::PaintChildren(const views::PaintInfo& info) {
constexpr float kChildClipPadding = 2.5f; constexpr float kChildClipPadding = 2.5f;
const gfx::InsetsF padding(0, kChildClipPadding + opacities.left, 0, const gfx::InsetsF padding(0, kChildClipPadding + opacities.left, 0,
kChildClipPadding + opacities.right); kChildClipPadding + opacities.right);
clip_recorder.ClipPathWithAntiAliasing(GetInteriorPath( clip_recorder.ClipPathWithAntiAliasing(
paint_recording_scale, paint_recording_scale * GetStrokeThickness(), GetInteriorPath(paint_recording_scale, GetStrokeThickness(),
IsActive() ? 0 : controller_->GetStrokeThickness(), bounds(), padding)); GetBottomStrokeThickness(), bounds(), padding));
View::PaintChildren(info); View::PaintChildren(info);
} }
void Tab::OnPaint(gfx::Canvas* canvas) { void Tab::OnPaint(gfx::Canvas* canvas) {
// Don't paint if we're narrower than we can render correctly. (This should
// only happen during animations).
if (!MD::IsRefreshUi() && (width() < GetMinimumInactiveWidth()))
return;
gfx::Path clip; gfx::Path clip;
if (!controller_->ShouldPaintTab( if (!controller_->ShouldPaintTab(
this, this,
base::BindRepeating( base::BindRepeating(&GetBorderPath, canvas->image_scale(),
&GetBorderPath, canvas->image_scale(), GetStrokeThickness(), GetStrokeThickness(), GetBottomStrokeThickness(),
IsActive() ? 0 : controller_->GetStrokeThickness(), true, false), true, false),
&clip)) &clip))
return; return;
...@@ -1012,11 +852,11 @@ void Tab::OnPaint(gfx::Canvas* canvas) { ...@@ -1012,11 +852,11 @@ void Tab::OnPaint(gfx::Canvas* canvas) {
} }
void Tab::AddedToWidget() { void Tab::AddedToWidget() {
OnButtonColorMaybeChanged(); UpdateForegroundColors();
} }
void Tab::OnThemeChanged() { void Tab::OnThemeChanged() {
OnButtonColorMaybeChanged(); UpdateForegroundColors();
} }
void Tab::SetClosing(bool closing) { void Tab::SetClosing(bool closing) {
...@@ -1059,36 +899,13 @@ SkColor Tab::GetAlertIndicatorColor(TabAlertState state) const { ...@@ -1059,36 +899,13 @@ SkColor Tab::GetAlertIndicatorColor(TabAlertState state) const {
} }
} }
SkColor Tab::GetCloseTabButtonColor(
views::Button::ButtonState button_state) const {
// The theme provider may be null if we're not currently in a widget
// hierarchy.
const ui::ThemeProvider* theme_provider = GetThemeProvider();
if (!theme_provider)
return gfx::kPlaceholderColor;
int color_id;
switch (button_state) {
case views::Button::STATE_HOVERED:
color_id = ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_HOVER;
break;
case views::Button::STATE_PRESSED:
color_id = ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_PRESSED;
break;
default:
color_id = IsActive() ? ThemeProperties::COLOR_TAB_CLOSE_BUTTON_ACTIVE
: ThemeProperties::COLOR_TAB_CLOSE_BUTTON_INACTIVE;
}
return theme_provider->GetColor(color_id);
}
bool Tab::IsActive() const { bool Tab::IsActive() const {
return controller_->IsActiveTab(this); return controller_->IsActiveTab(this);
} }
void Tab::ActiveStateChanged() { void Tab::ActiveStateChanged() {
UpdateTabIconNeedsAttentionBlocked(); UpdateTabIconNeedsAttentionBlocked();
OnButtonColorMaybeChanged(); UpdateForegroundColors();
alert_indicator_button_->UpdateEnabledForMuteToggle(); alert_indicator_button_->UpdateEnabledForMuteToggle();
Layout(); Layout();
} }
...@@ -1098,12 +915,12 @@ void Tab::AlertStateChanged() { ...@@ -1098,12 +915,12 @@ void Tab::AlertStateChanged() {
} }
void Tab::FrameColorsChanged() { void Tab::FrameColorsChanged() {
OnButtonColorMaybeChanged(); UpdateForegroundColors();
SchedulePaint(); SchedulePaint();
} }
void Tab::SelectedStateChanged() { void Tab::SelectedStateChanged() {
OnButtonColorMaybeChanged(); UpdateForegroundColors();
} }
bool Tab::IsSelected() const { bool Tab::IsSelected() const {
...@@ -1178,11 +995,17 @@ void Tab::SetTabNeedsAttention(bool attention) { ...@@ -1178,11 +995,17 @@ void Tab::SetTabNeedsAttention(bool attention) {
} }
float Tab::GetStrokeThickness(bool should_paint_as_active) const { float Tab::GetStrokeThickness(bool should_paint_as_active) const {
return !MD::IsRefreshUi() || IsActive() || should_paint_as_active return (IsActive() || should_paint_as_active)
? controller_->GetStrokeThickness() ? controller_->GetStrokeThickness()
: 0; : 0;
} }
float Tab::GetBottomStrokeThickness(bool should_paint_as_active) const {
return (IsActive() || should_paint_as_active)
? 0
: controller_->GetStrokeThickness();
}
int Tab::GetWidthOfLargestSelectableRegion() const { int Tab::GetWidthOfLargestSelectableRegion() const {
// Assume the entire region to the left of the alert indicator and/or close // Assume the entire region to the left of the alert indicator and/or close
// buttons is available for click-to-select. If neither are visible, the // buttons is available for click-to-select. If neither are visible, the
...@@ -1205,15 +1028,11 @@ gfx::Insets Tab::GetContentsInsets() const { ...@@ -1205,15 +1028,11 @@ gfx::Insets Tab::GetContentsInsets() const {
// static // static
gfx::Insets Tab::GetContentsHorizontalInsets() { gfx::Insets Tab::GetContentsHorizontalInsets() {
return gfx::Insets(0, MD::IsRefreshUi() ? (GetCornerRadius() * 2) return gfx::Insets(0, GetCornerRadius() * 2);
: GetTabEndcapWidthForLayout());
} }
// static // static
int Tab::GetMinimumInactiveWidth() { int Tab::GetMinimumInactiveWidth() {
if (!MD::IsRefreshUi())
return GetContentsHorizontalInsets().width();
// Allow tabs to shrink until they appear to be 16 DIP wide excluding outer // Allow tabs to shrink until they appear to be 16 DIP wide excluding outer
// corners. // corners.
constexpr int kInteriorWidth = 16; constexpr int kInteriorWidth = 16;
...@@ -1229,10 +1048,10 @@ int Tab::GetMinimumActiveWidth() { ...@@ -1229,10 +1048,10 @@ int Tab::GetMinimumActiveWidth() {
// static // static
int Tab::GetStandardWidth() { int Tab::GetStandardWidth() {
constexpr int kRefreshTabWidth = 240 - kSeparatorThickness; // The standard tab width is 240 DIP including both separators.
constexpr int kLayoutWidth[] = {193, 193, 245, kRefreshTabWidth, constexpr int kTabWidth = 240;
kRefreshTabWidth}; // The overlap includes one separator, so subtract it here.
return GetOverlap() + kLayoutWidth[MD::GetMode()]; return kTabWidth + GetOverlap() - kSeparatorThickness;
} }
// static // static
...@@ -1249,18 +1068,19 @@ int Tab::GetCornerRadius() { ...@@ -1249,18 +1068,19 @@ int Tab::GetCornerRadius() {
// static // static
int Tab::GetDragInset() { int Tab::GetDragInset() {
return MD::IsRefreshUi() ? GetCornerRadius() : GetTabEndcapWidthForLayout(); return GetCornerRadius();
} }
// static // static
int Tab::GetOverlap() { int Tab::GetOverlap() {
// For refresh, overlap the separators. // Overlap the separators.
return MD::IsRefreshUi() ? (GetCornerRadius() * 2 + kSeparatorThickness) return GetCornerRadius() * 2 + kSeparatorThickness;
: GetTabEndcapWidthForLayout();
} }
// static // static
int Tab::GetTabSeparatorHeight() { int Tab::GetTabSeparatorHeight() {
constexpr int kTabSeparatorHeight = 20;
constexpr int kTabSeparatorTouchHeight = 24;
return MD::IsTouchOptimizedUiEnabled() ? kTabSeparatorTouchHeight return MD::IsTouchOptimizedUiEnabled() ? kTabSeparatorTouchHeight
: kTabSeparatorHeight; : kTabSeparatorHeight;
} }
...@@ -1334,6 +1154,28 @@ void Tab::PaintTabBackground(gfx::Canvas* canvas, ...@@ -1334,6 +1154,28 @@ void Tab::PaintTabBackground(gfx::Canvas* canvas,
: SK_ColorTRANSPARENT; : SK_ColorTRANSPARENT;
const SkColor stroke_color = controller_->GetToolbarTopSeparatorColor(); const SkColor stroke_color = controller_->GetToolbarTopSeparatorColor();
const bool paint_hover_effect = !active && hover_controller_.ShouldDraw(); const bool paint_hover_effect = !active && hover_controller_.ShouldDraw();
const float scale = canvas->image_scale();
const float stroke_thickness = GetStrokeThickness(active);
const float bottom_offset = GetBottomStrokeThickness(active);
const auto paint_fill = [&](gfx::Canvas* canvas) {
// When there's a border, we want the stroke to cover up the edge of the
// fill path (https://crbug.com/873003), so set the fill path halfway
// between the inner path and the border paths. When there's no stroke,
// |stroke_thickness| is 0 and the fill, inner, and stroke paths are all
// identical.
gfx::Path fill_path =
GetInteriorPath(scale, stroke_thickness / 2, bottom_offset, bounds());
PaintTabBackgroundFill(canvas, fill_path, active, paint_hover_effect,
active_color, inactive_color, fill_id, y_inset);
};
const auto paint_stroke = [&](gfx::Canvas* canvas) {
gfx::Path interior_path =
GetInteriorPath(scale, stroke_thickness, bottom_offset, bounds());
gfx::Path outer_path = GetBorderPath(scale, stroke_thickness, bottom_offset,
false, false, bounds());
PaintTabBackgroundStroke(canvas, interior_path, outer_path, active,
stroke_color);
};
// If there is a |fill_id| we don't try to cache. This could be improved // 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 // but would require knowing then the image from the ThemeProvider had been
...@@ -1344,65 +1186,33 @@ void Tab::PaintTabBackground(gfx::Canvas* canvas, ...@@ -1344,65 +1186,33 @@ void Tab::PaintTabBackground(gfx::Canvas* canvas,
// on every invalidation and we would need to invalidate the cache based on // on every invalidation and we would need to invalidate the cache based on
// the hover states. // the hover states.
// //
// Finally, in refresh, we don't cache for non-integral scale factors, since // Finally, we don't cache for non-integral scale factors, since tabs draw
// tabs draw with slightly different offsets so as to pixel-align the layout // with slightly different offsets so as to pixel-align the layout rect (see
// rect (see ScaleAndAlignBounds()). // ScaleAndAlignBounds()).
const float scale = canvas->image_scale(); if (fill_id || paint_hover_effect || (std::trunc(scale) != scale)) {
const float stroke_thickness = GetStrokeThickness(active); paint_fill(canvas);
const float bottom_offset = active ? 0 : controller_->GetStrokeThickness();
if (fill_id || paint_hover_effect ||
(MD::IsRefreshUi() && (std::trunc(scale) != scale))) {
// When there's a border, we want the stroke to cover up the edge of the
// fill path (https://crbug.com/873003), so set the fill path halfway
// between the inner path and the border paths. When there's no stroke,
// |stroke_thickness| is 0 and the fill, inner, and stroke paths are all
// identical. Avoid doing this on pre-refresh since strokes may be
// transparent.
gfx::Path fill_path = GetInteriorPath(
scale, MD::IsRefreshUi() ? stroke_thickness / 2 : stroke_thickness,
bottom_offset, bounds());
PaintTabBackgroundFill(canvas, fill_path, active, paint_hover_effect,
active_color, inactive_color, fill_id, y_inset);
if (stroke_thickness > 0) { if (stroke_thickness > 0) {
gfx::Path interior_path =
GetInteriorPath(scale, stroke_thickness, bottom_offset, bounds());
gfx::Path outer_path = GetBorderPath(
scale, stroke_thickness, bottom_offset, false, false, bounds());
gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr); gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
if (clip) if (clip)
canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true); canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
PaintTabBackgroundStroke(canvas, interior_path, outer_path, active, paint_stroke(canvas);
stroke_color);
} }
} else { } else {
BackgroundCache& cache = BackgroundCache& cache =
active ? background_active_cache_ : background_inactive_cache_; active ? background_active_cache_ : background_inactive_cache_;
if (!cache.CacheKeyMatches(scale, size(), active_color, inactive_color, if (!cache.CacheKeyMatches(scale, size(), active_color, inactive_color,
stroke_color, stroke_thickness)) { stroke_color, stroke_thickness)) {
// See the comment in the non-caching case above for why we divide
// |stroke_thickness| by 2 on refresh.
gfx::Path fill_path = GetInteriorPath(
scale, MD::IsRefreshUi() ? stroke_thickness / 2 : stroke_thickness,
bottom_offset, bounds());
cc::PaintRecorder recorder; cc::PaintRecorder recorder;
{ {
gfx::Canvas cache_canvas( gfx::Canvas cache_canvas(
recorder.beginRecording(size().width(), size().height()), scale); recorder.beginRecording(size().width(), size().height()), scale);
PaintTabBackgroundFill(&cache_canvas, fill_path, active, paint_fill(&cache_canvas);
paint_hover_effect, active_color, inactive_color,
fill_id, y_inset);
cache.fill_record = recorder.finishRecordingAsPicture(); cache.fill_record = recorder.finishRecordingAsPicture();
} }
if (stroke_thickness > 0) { if (stroke_thickness > 0) {
gfx::Path interior_path =
GetInteriorPath(scale, stroke_thickness, bottom_offset, bounds());
gfx::Path border_path = GetBorderPath(
scale, stroke_thickness, bottom_offset, false, false, bounds());
gfx::Canvas cache_canvas( gfx::Canvas cache_canvas(
recorder.beginRecording(size().width(), size().height()), scale); recorder.beginRecording(size().width(), size().height()), scale);
PaintTabBackgroundStroke(&cache_canvas, interior_path, border_path, paint_stroke(&cache_canvas);
active, stroke_color);
cache.stroke_record = recorder.finishRecordingAsPicture(); cache.stroke_record = recorder.finishRecordingAsPicture();
} }
...@@ -1627,33 +1437,11 @@ void Tab::UpdateIconVisibility() { ...@@ -1627,33 +1437,11 @@ void Tab::UpdateIconVisibility() {
// We also check this for active tabs so that the extra padding doesn't pop // We also check this for active tabs so that the extra padding doesn't pop
// in and out as you switch tabs. // in and out as you switch tabs.
extra_padding_before_content_ = large_enough_for_close_button; extra_padding_before_content_ = large_enough_for_close_button;
if (DCHECK_IS_ON()) {
const int extra_left_padding =
MD::IsRefreshUi()
? kRefreshExtraLeftPaddingToBalanceCloseButtonPadding
: kExtraLeftPaddingToBalanceCloseButtonPadding;
DCHECK(!extra_padding_before_content_ ||
extra_left_padding <= available_width);
if (extra_padding_before_content_)
available_width -= extra_left_padding;
}
} }
if (MD::IsRefreshUi()) { extra_alert_indicator_padding_ = showing_alert_indicator_ &&
extra_alert_indicator_padding_ = showing_alert_indicator_ && showing_close_button_ &&
showing_close_button_ && large_enough_for_close_button;
large_enough_for_close_button;
if (DCHECK_IS_ON()) {
const int extra_alert_padding =
MD::IsTouchOptimizedUiEnabled()
? kTouchableRefreshAlertIndicatorCloseButtonPadding
: kRefreshAlertIndicatorCloseButtonPadding;
DCHECK(!extra_alert_indicator_padding_ ||
extra_alert_padding <= available_width);
}
}
} }
bool Tab::ShouldRenderAsNormalTab() const { bool Tab::ShouldRenderAsNormalTab() const {
...@@ -1662,9 +1450,6 @@ bool Tab::ShouldRenderAsNormalTab() const { ...@@ -1662,9 +1450,6 @@ bool Tab::ShouldRenderAsNormalTab() const {
} }
Tab::SeparatorOpacities Tab::GetSeparatorOpacities(bool for_layout) const { Tab::SeparatorOpacities Tab::GetSeparatorOpacities(bool for_layout) const {
if (!MD::IsRefreshUi())
return SeparatorOpacities();
// Something should visually separate tabs from each other and any adjacent // Something should visually separate tabs from each other and any adjacent
// new tab button. Normally, active and hovered tabs draw distinct shapes // new tab button. Normally, active and hovered tabs draw distinct shapes
// (via different background colors) and thus need no separators, while // (via different background colors) and thus need no separators, while
...@@ -1763,6 +1548,7 @@ float Tab::GetThrobValue() const { ...@@ -1763,6 +1548,7 @@ float Tab::GetThrobValue() const {
// Wrapping in closure to only compute offset when needed (animate or hover). // Wrapping in closure to only compute offset when needed (animate or hover).
const auto offset = [=] { const auto offset = [=] {
constexpr float kSelectedTabThrobScale = 0.95f - kSelectedTabOpacity;
const float opacity = GetHoverOpacity(); const float opacity = GetHoverOpacity();
return is_selected ? (kSelectedTabThrobScale * opacity) : opacity; return is_selected ? (kSelectedTabThrobScale * opacity) : opacity;
}; };
...@@ -1775,16 +1561,6 @@ float Tab::GetThrobValue() const { ...@@ -1775,16 +1561,6 @@ float Tab::GetThrobValue() const {
return val; return val;
} }
void Tab::OnButtonColorMaybeChanged() {
// The theme provider may be null if we're not currently in a widget
// hierarchy.
const ui::ThemeProvider* theme_provider = GetThemeProvider();
if (!theme_provider)
return;
UpdateForegroundColors();
}
void Tab::UpdateTabIconNeedsAttentionBlocked() { void Tab::UpdateTabIconNeedsAttentionBlocked() {
// Only show the blocked attention indicator on non-active tabs. For active // Only show the blocked attention indicator on non-active tabs. For active
// tabs, the user sees the dialog blocking the tab, so there's no point to it // tabs, the user sees the dialog blocking the tab, so there's no point to it
...@@ -1798,10 +1574,16 @@ void Tab::UpdateTabIconNeedsAttentionBlocked() { ...@@ -1798,10 +1574,16 @@ void Tab::UpdateTabIconNeedsAttentionBlocked() {
} }
void Tab::UpdateForegroundColors() { void Tab::UpdateForegroundColors() {
// These ratios are calculated from the default colors specified in the // The theme provider may be null if we're not currently in a widget
// Material Refresh design document. Active/inactive are the contrast ratios // hierarchy.
// of the close X against the tab background. Hovered/pressed are the contrast const ui::ThemeProvider* theme_provider = GetThemeProvider();
// ratios of the highlight circle against the tab background. if (!theme_provider)
return;
// These ratios are calculated from the default Chrome theme colors.
// Active/inactive are the contrast ratios of the close X against the tab
// background. Hovered/pressed are the contrast ratios of the highlight circle
// against the tab background.
constexpr float kMinimumActiveContrastRatio = 6.05f; constexpr float kMinimumActiveContrastRatio = 6.05f;
constexpr float kMinimumInactiveContrastRatio = 4.61f; constexpr float kMinimumInactiveContrastRatio = 4.61f;
constexpr float kMinimumHoveredContrastRatio = 5.02f; constexpr float kMinimumHoveredContrastRatio = 5.02f;
...@@ -1831,16 +1613,10 @@ void Tab::UpdateForegroundColors() { ...@@ -1831,16 +1613,10 @@ void Tab::UpdateForegroundColors() {
title_->SetEnabledColor(tab_title_color); title_->SetEnabledColor(tab_title_color);
const SkColor base_icon_color = const SkColor base_hovered_color = theme_provider->GetColor(
MD::GetMode() == ui::MaterialDesignController::MATERIAL_TOUCH_OPTIMIZED ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_HOVER);
? GetCloseTabButtonColor(views::Button::STATE_NORMAL) const SkColor base_pressed_color = theme_provider->GetColor(
: tab_title_color; ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_PRESSED);
const SkColor base_hovered_pressed_icon_color =
MD::IsNewerMaterialUi() ? base_icon_color : SK_ColorWHITE;
const SkColor base_hovered_color =
GetCloseTabButtonColor(views::Button::STATE_HOVERED);
const SkColor base_pressed_color =
GetCloseTabButtonColor(views::Button::STATE_PRESSED);
const auto get_color_for_contrast_ratio = [](SkColor fg_color, const auto get_color_for_contrast_ratio = [](SkColor fg_color,
SkColor bg_color, SkColor bg_color,
...@@ -1851,7 +1627,7 @@ void Tab::UpdateForegroundColors() { ...@@ -1851,7 +1627,7 @@ void Tab::UpdateForegroundColors() {
}; };
const SkColor generated_icon_color = get_color_for_contrast_ratio( const SkColor generated_icon_color = get_color_for_contrast_ratio(
base_icon_color, tab_bg_color, tab_title_color, tab_bg_color,
IsActive() ? kMinimumActiveContrastRatio : kMinimumInactiveContrastRatio); IsActive() ? kMinimumActiveContrastRatio : kMinimumInactiveContrastRatio);
const SkColor generated_hovered_color = get_color_for_contrast_ratio( const SkColor generated_hovered_color = get_color_for_contrast_ratio(
base_hovered_color, tab_bg_color, kMinimumHoveredContrastRatio); base_hovered_color, tab_bg_color, kMinimumHoveredContrastRatio);
...@@ -1859,10 +1635,10 @@ void Tab::UpdateForegroundColors() { ...@@ -1859,10 +1635,10 @@ void Tab::UpdateForegroundColors() {
base_pressed_color, tab_bg_color, kMinimumPressedContrastRatio); base_pressed_color, tab_bg_color, kMinimumPressedContrastRatio);
const SkColor generated_hovered_icon_color = const SkColor generated_hovered_icon_color =
color_utils::GetColorWithMinimumContrast(base_hovered_pressed_icon_color, color_utils::GetColorWithMinimumContrast(tab_title_color,
generated_hovered_color); generated_hovered_color);
const SkColor generated_pressed_icon_color = const SkColor generated_pressed_icon_color =
color_utils::GetColorWithMinimumContrast(base_hovered_pressed_icon_color, color_utils::GetColorWithMinimumContrast(tab_title_color,
generated_pressed_color); generated_pressed_color);
close_button_->SetIconColors( close_button_->SetIconColors(
generated_icon_color, generated_hovered_icon_color, generated_icon_color, generated_hovered_icon_color,
......
...@@ -54,8 +54,8 @@ class Tab : public gfx::AnimationDelegate, ...@@ -54,8 +54,8 @@ class Tab : public gfx::AnimationDelegate,
// The Tab's class name. // The Tab's class name.
static const char kViewClassName[]; static const char kViewClassName[];
// Under refresh, thickness in DIPs of the separator painted on the left and // Thickness in DIPs of the separator painted on the left and right edges of
// right edges of the tab. // the tab.
static constexpr int kSeparatorThickness = 1; static constexpr int kSeparatorThickness = 1;
// When the content's width of the tab shrinks to below this size we should // When the content's width of the tab shrinks to below this size we should
...@@ -123,9 +123,6 @@ class Tab : public gfx::AnimationDelegate, ...@@ -123,9 +123,6 @@ class Tab : public gfx::AnimationDelegate,
// Returns the color used for the alert indicator icon. // Returns the color used for the alert indicator icon.
SkColor GetAlertIndicatorColor(TabAlertState state) const; SkColor GetAlertIndicatorColor(TabAlertState state) const;
// Returns the color to be used for the tab close button.
SkColor GetCloseTabButtonColor(views::Button::ButtonState button_state) const;
// Returns true if this tab is the active tab. // Returns true if this tab is the active tab.
bool IsActive() const; bool IsActive() const;
...@@ -177,12 +174,15 @@ class Tab : public gfx::AnimationDelegate, ...@@ -177,12 +174,15 @@ class Tab : public gfx::AnimationDelegate,
bool mouse_hovered() const { return mouse_hovered_; } bool mouse_hovered() const { return mouse_hovered_; }
// Returns the thickness of the stroke drawn around the tab. If // Returns the thickness of the stroke drawn around the top and sides of the
// |should_paint_as_active| is true, the tab is treated as an active tab // tab. Only active tabs may have a stroke, and not in all cases. If there
// regardless of its true current state; this affects Refresh, which never // is no stroke, returns 0. If |should_paint_as_active| is true, the tab is
// paints strokes on inactive tabs. // treated as an active tab regardless of its true current state.
float GetStrokeThickness(bool should_paint_as_active = false) const; float GetStrokeThickness(bool should_paint_as_active = false) const;
// Returns the thickness of the stroke drawn below the tab.
float GetBottomStrokeThickness(bool should_paint_as_active = false) const;
// Returns the width of the largest part of the tab that is available for the // Returns the width of the largest part of the tab that is available for the
// user to click to select/activate the tab. // user to click to select/activate the tab.
int GetWidthOfLargestSelectableRegion() const; int GetWidthOfLargestSelectableRegion() const;
...@@ -274,8 +274,7 @@ class Tab : public gfx::AnimationDelegate, ...@@ -274,8 +274,7 @@ class Tab : public gfx::AnimationDelegate,
bool active, bool active,
SkColor color); SkColor color);
// Paints the separator lines on the left and right edge of the tab if in // Paints the separator lines on the left and right edge of the tab.
// material refresh mode.
void PaintSeparators(gfx::Canvas* canvas); void PaintSeparators(gfx::Canvas* canvas);
// Computes which icons are visible in the tab. Should be called everytime // Computes which icons are visible in the tab. Should be called everytime
...@@ -299,11 +298,6 @@ class Tab : public gfx::AnimationDelegate, ...@@ -299,11 +298,6 @@ class Tab : public gfx::AnimationDelegate,
// tab title change and pulsing. // tab title change and pulsing.
float GetThrobValue() const; float GetThrobValue() const;
// Recalculates the correct |button_color_| and resets the title, alert
// indicator, and close button colors if necessary. This should be called any
// time the theme or active state may have changed.
void OnButtonColorMaybeChanged();
// Updates the blocked attention state of the |icon_|. This only updates // Updates the blocked attention state of the |icon_|. This only updates
// state; it is the responsibility of the caller to request a paint. // state; it is the responsibility of the caller to request a paint.
void UpdateTabIconNeedsAttentionBlocked(); void UpdateTabIconNeedsAttentionBlocked();
......
...@@ -65,8 +65,8 @@ class TabCloseButton : public views::ImageButton, ...@@ -65,8 +65,8 @@ class TabCloseButton : public views::ImageButton,
// Draw the close "X" glyph. // Draw the close "X" glyph.
void DrawCloseGlyph(gfx::Canvas* canvas, ButtonState state); void DrawCloseGlyph(gfx::Canvas* canvas, ButtonState state);
// In material refresh mode, calculates opacity based on the current state of // Calculates opacity based on the current state of the hover animation on the
// the hover animation on the parent tab. // parent tab.
SkAlpha GetOpacity(); SkAlpha GetOpacity();
MouseEventCallback mouse_event_callback_; MouseEventCallback mouse_event_callback_;
......
...@@ -36,9 +36,9 @@ class TabController { ...@@ -36,9 +36,9 @@ class TabController {
// Returns true if multiple selection is supported. // Returns true if multiple selection is supported.
virtual bool SupportsMultipleSelection() = 0; virtual bool SupportsMultipleSelection() = 0;
// Under Refresh, returns where the new tab button should be placed. This is // Returns where the new tab button should be placed. This is needed to
// needed to determine which tab separators need to be faded in/out while // determine which tab separators need to be faded in/out while animating into
// animating into position. // position.
virtual NewTabButtonPosition GetNewTabButtonPosition() const = 0; virtual NewTabButtonPosition GetNewTabButtonPosition() const = 0;
// Returns true if the close button for the given tab is forced to be hidden. // Returns true if the close button for the given tab is forced to be hidden.
...@@ -130,8 +130,8 @@ class TabController { ...@@ -130,8 +130,8 @@ class TabController {
border_callback, border_callback,
gfx::Path* clip) = 0; gfx::Path* clip) = 0;
// Returns the thickness of the stroke around all tabs (for pre-refresh) or // Returns the thickness of the stroke around the active tab in DIP. Returns
// the active tab (for refresh) in DIP. Returns 0 if there is no stroke. // 0 if there is no stroke.
virtual int GetStrokeThickness() const = 0; virtual int GetStrokeThickness() const = 0;
// Returns true if tab loading throbbers can be painted to a composited layer. // Returns true if tab loading throbbers can be painted to a composited layer.
...@@ -147,7 +147,7 @@ class TabController { ...@@ -147,7 +147,7 @@ class TabController {
// state of the window. // state of the window.
virtual SkColor GetToolbarTopSeparatorColor() const = 0; virtual SkColor GetToolbarTopSeparatorColor() const = 0;
// Under Refresh, returns the color of the separator between the tabs. // Returns the color of the separator between the tabs.
virtual SkColor GetTabSeparatorColor() const = 0; virtual SkColor GetTabSeparatorColor() const = 0;
// Returns the tab background color based on both the |state| of the tab and // Returns the tab background color based on both the |state| of the tab and
......
...@@ -186,15 +186,6 @@ class TabStripTest : public ChromeViewsTestBase, ...@@ -186,15 +186,6 @@ class TabStripTest : public ChromeViewsTestBase,
return delegate; return delegate;
} }
bool IsTabShowingCloseButton(Tab* tab) {
ui::MouseEvent event(ui::ET_MOUSE_ENTERED, gfx::Point(0, 0),
gfx::Point(0, 0), ui::EventTimeForNow(), 0, 0);
// In Refresh, close buttons on inactive tabs are never visible until the
// tab is hovered. It's harmless to do this in other cases.
tab->OnMouseEntered(event);
return tab->showing_close_button_;
}
bool IsShowingAttentionIndicator(Tab* tab) { bool IsShowingAttentionIndicator(Tab* tab) {
return tab->icon_->ShowingAttentionIndicator(); return tab->icon_->ShowingAttentionIndicator();
} }
...@@ -443,9 +434,9 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenStacked) { ...@@ -443,9 +434,9 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenStacked) {
Tab* tab2 = tab_strip_->tab_at(2); Tab* tab2 = tab_strip_->tab_at(2);
// Ensure that all tab close buttons are initially visible. // Ensure that all tab close buttons are initially visible.
EXPECT_TRUE(IsTabShowingCloseButton(tab0)); EXPECT_TRUE(tab0->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab1)); EXPECT_TRUE(tab1->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab2)); EXPECT_TRUE(tab2->showing_close_button_);
// Enter stacked layout mode and verify this sets |touch_layout_|. // Enter stacked layout mode and verify this sets |touch_layout_|.
ASSERT_FALSE(touch_layout()); ASSERT_FALSE(touch_layout());
...@@ -454,18 +445,18 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenStacked) { ...@@ -454,18 +445,18 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenStacked) {
// Only the close button of the active tab should be visible in stacked // Only the close button of the active tab should be visible in stacked
// layout mode. // layout mode.
EXPECT_FALSE(IsTabShowingCloseButton(tab0)); EXPECT_FALSE(tab0->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab1)); EXPECT_TRUE(tab1->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab2)); EXPECT_FALSE(tab2->showing_close_button_);
// An inactive tab added to the tabstrip should not show // An inactive tab added to the tabstrip should not show
// its tab close button. // its tab close button.
controller_->AddTab(3, false); controller_->AddTab(3, false);
Tab* tab3 = tab_strip_->tab_at(3); Tab* tab3 = tab_strip_->tab_at(3);
EXPECT_FALSE(IsTabShowingCloseButton(tab0)); EXPECT_FALSE(tab0->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab1)); EXPECT_TRUE(tab1->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab2)); EXPECT_FALSE(tab2->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab3)); EXPECT_FALSE(tab3->showing_close_button_);
// After switching tabs, the previously-active tab should have its // After switching tabs, the previously-active tab should have its
// tab close button hidden and the newly-active tab should show // tab close button hidden and the newly-active tab should show
...@@ -473,26 +464,26 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenStacked) { ...@@ -473,26 +464,26 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenStacked) {
tab_strip_->SelectTab(tab2); tab_strip_->SelectTab(tab2);
ASSERT_FALSE(tab1->IsActive()); ASSERT_FALSE(tab1->IsActive());
ASSERT_TRUE(tab2->IsActive()); ASSERT_TRUE(tab2->IsActive());
EXPECT_FALSE(IsTabShowingCloseButton(tab0)); EXPECT_FALSE(tab0->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab1)); EXPECT_FALSE(tab1->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab2)); EXPECT_TRUE(tab2->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab3)); EXPECT_FALSE(tab3->showing_close_button_);
// After closing the active tab, the tab which becomes active should // After closing the active tab, the tab which becomes active should
// show its tab close button. // show its tab close button.
tab_strip_->CloseTab(tab1, CLOSE_TAB_FROM_TOUCH); tab_strip_->CloseTab(tab1, CLOSE_TAB_FROM_TOUCH);
tab1 = nullptr; tab1 = nullptr;
ASSERT_TRUE(tab2->IsActive()); ASSERT_TRUE(tab2->IsActive());
EXPECT_FALSE(IsTabShowingCloseButton(tab0)); EXPECT_FALSE(tab0->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab2)); EXPECT_TRUE(tab2->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab3)); EXPECT_FALSE(tab3->showing_close_button_);
// All tab close buttons should be shown when disengaging stacked tab mode. // All tab close buttons should be shown when disengaging stacked tab mode.
tab_strip_->SetStackedLayout(false); tab_strip_->SetStackedLayout(false);
ASSERT_FALSE(touch_layout()); ASSERT_FALSE(touch_layout());
EXPECT_TRUE(IsTabShowingCloseButton(tab0)); EXPECT_TRUE(tab0->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab2)); EXPECT_TRUE(tab2->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab3)); EXPECT_TRUE(tab3->showing_close_button_);
} }
// Tests that the tab close buttons of non-active tabs are hidden when // Tests that the tab close buttons of non-active tabs are hidden when
...@@ -524,9 +515,9 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) { ...@@ -524,9 +515,9 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) {
ASSERT_FALSE(touch_layout()); ASSERT_FALSE(touch_layout());
// Ensure that all tab close buttons are initially visible. // Ensure that all tab close buttons are initially visible.
EXPECT_TRUE(IsTabShowingCloseButton(tab0)); EXPECT_TRUE(tab0->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab1)); EXPECT_TRUE(tab1->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab2)); EXPECT_TRUE(tab2->showing_close_button_);
// Shrink the tab sizes by adding more tabs. // Shrink the tab sizes by adding more tabs.
// An inactive tab added to the tabstrip, now each tab size is not // An inactive tab added to the tabstrip, now each tab size is not
...@@ -534,7 +525,7 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) { ...@@ -534,7 +525,7 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) {
// tab close button. // tab close button.
controller_->AddTab(3, false); controller_->AddTab(3, false);
Tab* tab3 = tab_strip_->tab_at(3); Tab* tab3 = tab_strip_->tab_at(3);
EXPECT_FALSE(IsTabShowingCloseButton(tab3)); EXPECT_FALSE(tab3->showing_close_button_);
// This inactive tab doesn't have alert button, but its favicon and // This inactive tab doesn't have alert button, but its favicon and
// title would be shown. // title would be shown.
...@@ -543,18 +534,18 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) { ...@@ -543,18 +534,18 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) {
EXPECT_TRUE(tab3->title_->visible()); EXPECT_TRUE(tab3->title_->visible());
// The active tab's close button still shows. // The active tab's close button still shows.
EXPECT_TRUE(IsTabShowingCloseButton(tab1)); EXPECT_TRUE(tab1->showing_close_button_);
// An active tab added to the tabstrip should show its tab close // An active tab added to the tabstrip should show its tab close
// button. // button.
controller_->AddTab(4, true); controller_->AddTab(4, true);
Tab* tab4 = tab_strip_->tab_at(4); Tab* tab4 = tab_strip_->tab_at(4);
ASSERT_TRUE(tab4->IsActive()); ASSERT_TRUE(tab4->IsActive());
EXPECT_TRUE(IsTabShowingCloseButton(tab4)); EXPECT_TRUE(tab4->showing_close_button_);
// The previous active button is now inactive so its close // The previous active button is now inactive so its close
// button should not show. // button should not show.
EXPECT_FALSE(IsTabShowingCloseButton(tab1)); EXPECT_FALSE(tab1->showing_close_button_);
// After switching tabs, the previously-active tab should have its // After switching tabs, the previously-active tab should have its
// tab close button hidden and the newly-active tab should show // tab close button hidden and the newly-active tab should show
...@@ -562,11 +553,11 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) { ...@@ -562,11 +553,11 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) {
tab_strip_->SelectTab(tab2); tab_strip_->SelectTab(tab2);
ASSERT_FALSE(tab4->IsActive()); ASSERT_FALSE(tab4->IsActive());
ASSERT_TRUE(tab2->IsActive()); ASSERT_TRUE(tab2->IsActive());
EXPECT_FALSE(IsTabShowingCloseButton(tab0)); EXPECT_FALSE(tab0->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab1)); EXPECT_FALSE(tab1->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab2)); EXPECT_TRUE(tab2->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab3)); EXPECT_FALSE(tab3->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab4)); EXPECT_FALSE(tab4->showing_close_button_);
// After closing the active tab, the tab which becomes active should // After closing the active tab, the tab which becomes active should
// show its tab close button. // show its tab close button.
...@@ -574,10 +565,10 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) { ...@@ -574,10 +565,10 @@ TEST_P(TabStripTest, TabCloseButtonVisibilityWhenNotStacked) {
tab2 = nullptr; tab2 = nullptr;
ASSERT_TRUE(tab3->IsActive()); ASSERT_TRUE(tab3->IsActive());
DoLayout(); DoLayout();
EXPECT_FALSE(IsTabShowingCloseButton(tab0)); EXPECT_FALSE(tab0->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab1)); EXPECT_FALSE(tab1->showing_close_button_);
EXPECT_TRUE(IsTabShowingCloseButton(tab3)); EXPECT_TRUE(tab3->showing_close_button_);
EXPECT_FALSE(IsTabShowingCloseButton(tab4)); EXPECT_FALSE(tab4->showing_close_button_);
} }
TEST_P(TabStripTest, GetEventHandlerForOverlappingArea) { TEST_P(TabStripTest, GetEventHandlerForOverlappingArea) {
......
...@@ -719,8 +719,7 @@ TEST_F(TabTest, TitleTextHasSufficientContrast) { ...@@ -719,8 +719,7 @@ TEST_F(TabTest, TitleTextHasSufficientContrast) {
SkColor fg_active; SkColor fg_active;
SkColor bg_inactive; SkColor bg_inactive;
SkColor fg_inactive; SkColor fg_inactive;
}; } color_schemes[] = {
ColorScheme color_schemes[] = {
{ {
SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
}, },
...@@ -731,8 +730,15 @@ TEST_F(TabTest, TitleTextHasSufficientContrast) { ...@@ -731,8 +730,15 @@ TEST_F(TabTest, TitleTextHasSufficientContrast) {
kDarkGray, kLightGray, kDarkGray, kLightGray, kDarkGray, kLightGray, kDarkGray, kLightGray,
}, },
}; };
// Create a tab inside a Widget, so it has a theme provider, so the call to
// UpdateForegroundColors() below doesn't no-op.
Widget widget;
InitWidget(&widget);
FakeTabController controller; FakeTabController controller;
Tab tab(&controller, nullptr); Tab tab(&controller, nullptr);
widget.GetContentsView()->AddChildView(&tab);
for (const auto& colors : color_schemes) { for (const auto& colors : color_schemes) {
controller.SetTabColors(colors.bg_active, colors.fg_active, controller.SetTabColors(colors.bg_active, colors.fg_active,
colors.bg_inactive, colors.fg_inactive); colors.bg_inactive, colors.fg_inactive);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment