blob: eb6789e6212b6ab4059ccf394434a0d6e3661900 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/tabs/tab_style.h"
#include <array>
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/tabs/features.h"
#include "chrome/browser/ui/ui_features.h"
#include "ui/base/ui_base_features.h"
#include "ui/color/color_provider.h"
#include "ui/gfx/color_utils.h"
#include "ui/views/layout/layout_provider.h"
namespace {
// Thickness in DIPs of the separator painted on the left and right edges of
// the tab.
constexpr int kChromeRefreshSeparatorThickness = 2;
constexpr int kChromeRefreshSeparatorHorizontalMargin = 2;
// TODO (crbug.com/1451400): This constant should be in LayoutConstants.
constexpr int kChromeRefreshSeparatorHeight = 16;
// The padding from the top of the tab to the content area.
constexpr int kChromeRefreshTabVerticalPadding = 6;
constexpr int kChromeRefreshTabHorizontalPadding = 8;
// The standard tab width is 232 DIP, excluding separators and overlap.
constexpr int kTabWidth = 232;
} // namespace
TabStyle::~TabStyle() = default;
int TabStyle::GetStandardHeight() const {
return GetLayoutConstant(TAB_STRIP_HEIGHT);
}
int TabStyle::GetStandardWidth(const bool is_split) const {
if (is_split) {
// Split tabs appear as half width with one bottom extension. They also must
// include half the tab overlap as the tabs fill the space between them.
return kTabWidth / 2 + GetBottomCornerRadius() + GetTabOverlap() / 2;
} else {
// The full width includes two extensions with the bottom corner radius.
return kTabWidth + 2 * GetBottomCornerRadius();
}
}
int TabStyle::GetPinnedWidth(const bool is_split) const {
constexpr int kTabPinnedContentWidth = 24;
const int standard_pinned_width = kTabPinnedContentWidth +
GetContentsInsets().left() +
GetContentsInsets().right();
if (is_split) {
// Split tabs will recoup half of the tab overlap to reduce extra
// whitespace.
return standard_pinned_width - GetTabOverlap() / 2;
}
return standard_pinned_width;
}
int TabStyle::GetMinimumActiveWidth(const bool is_split) const {
const int close_button_size = GetLayoutConstant(TAB_CLOSE_BUTTON_SIZE);
const gfx::Insets insets = GetContentsInsets();
const int min_active_width =
close_button_size + insets.left() + insets.right();
if (base::FeatureList::IsEnabled(tabs::kScrollableTabStrip)) {
return std::max(
min_active_width,
base::GetFieldTrialParamByFeatureAsInt(
tabs::kScrollableTabStrip,
tabs::kMinimumTabWidthFeatureParameterName, min_active_width));
}
if (is_split) {
// Only have one set of horizontal padding between tabs in an active split.
return min_active_width - kChromeRefreshTabHorizontalPadding / 2;
}
return min_active_width;
}
int TabStyle::GetMinimumInactiveWidth() const {
// Allow tabs to shrink until they appear to be 16 DIP wide excluding
// outer corners.
constexpr int kInteriorWidth = 16;
// The overlap contains the trailing separator that is part of the interior
// width; avoid double-counting it.
int min_inactive_width =
kInteriorWidth - GetSeparatorSize().width() + GetTabOverlap();
if (base::FeatureList::IsEnabled(tabs::kScrollableTabStrip)) {
return std::max(
min_inactive_width,
base::GetFieldTrialParamByFeatureAsInt(
tabs::kScrollableTabStrip,
tabs::kMinimumTabWidthFeatureParameterName, min_inactive_width));
}
return min_inactive_width;
}
int TabStyle::GetTopCornerRadius() const {
return 10;
}
int TabStyle::GetBottomCornerRadius() const {
return 12;
}
int TabStyle::GetTabOverlap() const {
// The overlap removes the width and the margins of the separator.
const float total_separator_width =
GetSeparatorMargins().width() + GetSeparatorSize().width();
return 2 * GetBottomCornerRadius() - total_separator_width;
}
gfx::Size TabStyle::GetPreviewImageSize() const {
constexpr float kTabHoverCardPreviewImageAspectRatio = 16.0f / 9.0f;
const int width = GetStandardWidth(/*is_split*/ false);
return gfx::Size(width, width / kTabHoverCardPreviewImageAspectRatio);
}
gfx::Size TabStyle::GetSeparatorSize() const {
return gfx::Size(kChromeRefreshSeparatorThickness,
kChromeRefreshSeparatorHeight);
}
gfx::Insets TabStyle::GetSeparatorMargins() const {
return gfx::Insets::TLBR(GetLayoutConstant(TAB_STRIP_PADDING),
kChromeRefreshSeparatorHorizontalMargin,
GetLayoutConstant(TAB_STRIP_PADDING),
kChromeRefreshSeparatorHorizontalMargin);
}
int TabStyle::GetSeparatorCornerRadius() const {
return GetSeparatorSize().width() / 2;
}
int TabStyle::GetDragHandleExtension(int height) const {
return 6;
}
SkColor TabStyle::GetTabBackgroundColor(
const TabSelectionState state,
const bool hovered,
const bool frame_active,
const ui::ColorProvider& color_provider) const {
switch (state) {
case TabStyle::TabSelectionState::kActive: {
constexpr std::array<ui::ColorId, 2> kActiveColorIds = {
kColorTabBackgroundActiveFrameInactive,
kColorTabBackgroundActiveFrameActive};
return color_provider.GetColor(kActiveColorIds[frame_active]);
}
case TabStyle::TabSelectionState::kSelected: {
constexpr std::array<std::array<ui::ColorId, 2>, 2> kSelectedColorIds = {
{{kColorTabBackgroundSelectedFrameInactive,
kColorTabBackgroundSelectedFrameActive},
{kColorTabBackgroundSelectedHoverFrameInactive,
kColorTabBackgroundSelectedHoverFrameActive}}};
return color_provider.GetColor(kSelectedColorIds[hovered][frame_active]);
}
case TabStyle::TabSelectionState::kInactive: {
constexpr std::array<std::array<ui::ColorId, 2>, 2> kInactiveColorIds = {
{{kColorTabBackgroundInactiveFrameInactive,
kColorTabBackgroundInactiveFrameActive},
{kColorTabBackgroundInactiveHoverFrameInactive,
kColorTabBackgroundInactiveHoverFrameActive}}};
return color_provider.GetColor(kInactiveColorIds[hovered][frame_active]);
}
default:
NOTREACHED();
}
}
gfx::Insets TabStyle::GetContentsInsets() const {
return gfx::Insets::TLBR(
kChromeRefreshTabVerticalPadding + GetLayoutConstant(TAB_STRIP_PADDING),
GetBottomCornerRadius() + kChromeRefreshTabHorizontalPadding,
kChromeRefreshTabVerticalPadding + GetLayoutConstant(TAB_STRIP_PADDING),
GetBottomCornerRadius() + kChromeRefreshTabHorizontalPadding);
}
float TabStyle::GetSelectedTabOpacity() const {
return kDefaultSelectedTabOpacity;
}
// static
const TabStyle* TabStyle::Get() {
static TabStyle* const tab_style = static_cast<TabStyle*>(new TabStyle());
return tab_style;
}