Commit 0a83f2b0 authored by Allen Bauer's avatar Allen Bauer Committed by Commit Bot

Adjust the position of the tab separator based on NTB position.

Bug: 842798
Change-Id: I2ccf920a119bece954ff037fed8e0e18cedadf25
Reviewed-on: https://chromium-review.googlesource.com/1113505
Commit-Queue: Allen Bauer <kylixrd@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571483}
parent d57122a3
......@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/debug/alias.h"
#include "base/i18n/rtl.h"
#include "base/macros.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/utf_string_conversions.h"
......@@ -95,6 +96,10 @@ constexpr float kSelectedTabThrobScale = 0.95f - kSelectedTabOpacity;
constexpr int kTabSeparatorHeight = 20;
constexpr int kTabSeparatorTouchHeight = 24;
// Under refresh, thickness of the separator in dips painted on the left and
// right edges of the tab.
constexpr int kSeparatorThickness = 1;
// Under material refresh, the spec for the favicon or title text is 12dips from
// the left vertical edge of the tab. This edge is in the middle of the tab end
// cap. The end cap is 16dips, the middle of which is 8dips. This value is the
......@@ -799,16 +804,12 @@ void Tab::OnMouseMoved(const ui::MouseEvent& event) {
void Tab::OnMouseEntered(const ui::MouseEvent& event) {
mouse_hovered_ = true;
hover_controller_.Show(GlowHoverController::SUBTLE);
if (MD::IsRefreshUi())
RepaintSubsequentTab();
Layout();
}
void Tab::OnMouseExited(const ui::MouseEvent& event) {
mouse_hovered_ = false;
hover_controller_.Hide();
if (MD::IsRefreshUi())
RepaintSubsequentTab();
Layout();
}
......@@ -989,8 +990,6 @@ void Tab::ActiveStateChanged() {
}
OnButtonColorMaybeChanged();
alert_indicator_button_->UpdateEnabledForMuteToggle();
if (MD::IsRefreshUi())
RepaintSubsequentTab();
Layout();
}
......@@ -1140,14 +1139,15 @@ float Tab::GetInverseDiagonalSlope() {
// static
int Tab::GetOverlap() {
// We want to overlap the endcap portions entirely.
return GetTabEndcapWidth();
// We want to overlap the endcap portions entirely. Under refresh, we want to
// overlap by an extra dip on each end in order overlap the separators.
return GetTabEndcapWidth() + (MD::IsRefreshUi() ? kSeparatorThickness : 0);
}
void Tab::RepaintSubsequentTab() {
Tab* adjacent_tab = controller_->GetAdjacentTab(this, TabController::FORWARD);
if (adjacent_tab)
adjacent_tab->SchedulePaint();
// static
int Tab::GetTabSeparatorHeight() {
return MD::IsTouchOptimizedUiEnabled() ? kTabSeparatorTouchHeight
: kTabSeparatorHeight;
}
void Tab::MaybeAdjustLeftForPinnedTab(gfx::Rect* bounds,
......@@ -1292,7 +1292,7 @@ void Tab::PaintTabBackground(gfx::Canvas* canvas,
}
if (!active)
PaintSeparator(canvas);
PaintSeparators(canvas);
}
void Tab::PaintTabBackgroundFill(gfx::Canvas* canvas,
......@@ -1352,17 +1352,10 @@ void Tab::PaintTabBackgroundStroke(gfx::Canvas* canvas,
canvas->DrawPath(path, flags);
}
void Tab::PaintSeparator(gfx::Canvas* canvas) {
void Tab::PaintSeparators(gfx::Canvas* canvas) {
if (!MD::IsRefreshUi())
return;
// If the tab to the left is active, the separator on this tab should not be
// painted.
Tab* previous_tab =
controller_->GetAdjacentTab(this, TabController::BACKWARD);
if (previous_tab && previous_tab->IsActive())
return;
gfx::ScopedCanvas scoped_canvas(canvas);
const float scale = canvas->UndoDeviceScaleFactor();
......@@ -1370,34 +1363,68 @@ void Tab::PaintSeparator(gfx::Canvas* canvas) {
const gfx::RectF aligned_bounds =
ScaleAndAlignBounds(bounds(), endcap_width, scale);
gfx::RectF separator_bounds;
separator_bounds.set_size(gfx::SizeF(
scale, (MD::IsTouchOptimizedUiEnabled() ? kTabSeparatorTouchHeight
: kTabSeparatorHeight) *
scale));
separator_bounds.set_origin(gfx::PointF(
const float separator_height = GetTabSeparatorHeight() * scale;
gfx::RectF leading_separator_bounds(
aligned_bounds.x() + (endcap_width / 2) * scale,
aligned_bounds.y() +
(aligned_bounds.height() - separator_bounds.height()) / 2));
aligned_bounds.y() + (aligned_bounds.height() - separator_height) / 2,
kSeparatorThickness * scale, separator_height);
gfx::RectF trailing_separator_bounds(
aligned_bounds.right() - (endcap_width / 2) * scale -
kSeparatorThickness * scale,
leading_separator_bounds.y(), kSeparatorThickness * scale,
separator_height);
gfx::PointF origin(bounds().origin());
origin.Scale(scale);
separator_bounds.Offset(-origin.x(), -origin.y());
// The following will paint the separator using an opacity that should
leading_separator_bounds.Offset(-origin.x(), -origin.y());
trailing_separator_bounds.Offset(-origin.x(), -origin.y());
// The following will paint the separators using an opacity that should
// cross-fade with the maximum hover animation value of this tab or the
// tab to the left. This will have the effect of fading out the separator
// while this tab's or the tab to the left's hover animation is progressing.
const double max_hover_value = std::max(
hover_controller_.GetAnimationValue(),
previous_tab ? previous_tab->hover_controller()->GetAnimationValue() : 0);
// subsequent tab. This will have the effect of fading out the separator
// while this tab's or the subsequent tab's hover animation is progressing.
// If the subsequent tab is active, don't consider its hover animation value.
// Without this active check and the subsequent tab is also dragged, the
// trailing separator on this tab will appear invisible (alpha = 0).
Tab* subsequent_tab = controller_->GetSubsequentTab(this);
float leading_alpha;
float trailing_alpha = leading_alpha =
std::max(hover_controller_.GetAnimationValue(),
subsequent_tab && !subsequent_tab->IsActive()
? subsequent_tab->hover_controller()->GetAnimationValue()
: 0);
// When the tab's bounds are animating, inversely fade the leading or trailing
// separator based on the NTB position, the tab's index, and how close to the
// target bounds this tab is.
NewTabButtonPosition ntb_position = controller_->GetNewTabButtonPosition();
const gfx::Rect target_bounds =
controller_->GetTabAnimationTargetBounds(this);
const int tab_width = std::max(width(), target_bounds.width());
const float target_alpha =
1.0 -
float{std::min(std::abs(x() - target_bounds.x()), tab_width)} / tab_width;
if (ntb_position != LEADING && controller_->IsFirstVisibleTab(this))
leading_alpha = target_alpha;
if (ntb_position != AFTER_TABS && controller_->IsLastVisibleTab(this))
trailing_alpha = target_alpha;
// Swap the alphas if in RTL mode.
if (base::i18n::IsRTL())
std::swap(leading_alpha, trailing_alpha);
cc::PaintFlags flags;
const SkColor separator_color = controller_->GetTabSeparatorColor();
flags.setAntiAlias(true);
flags.setColor(SkColorSetA(separator_color, gfx::Tween::IntValueBetween(
leading_alpha, SK_AlphaOPAQUE,
SK_AlphaTRANSPARENT)));
canvas->DrawRect(leading_separator_bounds, flags);
flags.setColor(
SkColorSetA(separator_color,
gfx::Tween::IntValueBetween(max_hover_value, SK_AlphaOPAQUE,
gfx::Tween::IntValueBetween(trailing_alpha, SK_AlphaOPAQUE,
SK_AlphaTRANSPARENT)));
canvas->DrawRect(separator_bounds, flags);
canvas->DrawRect(trailing_separator_bounds, flags);
}
void Tab::UpdateIconVisibility() {
......
......@@ -193,6 +193,9 @@ class Tab : public gfx::AnimationDelegate,
// of the tab, in DIP.
static int GetStrokeHeight();
// Returns the height of the separator between tabs.
static int GetTabSeparatorHeight();
// 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.)
......@@ -213,9 +216,6 @@ class Tab : public gfx::AnimationDelegate,
FRIEND_TEST_ALL_PREFIXES(TabStripTest,
TabCloseButtonVisibilityWhenNotStacked);
// Forces the tab to the right of this tab to repaint.
void RepaintSubsequentTab();
// Invoked from Layout to adjust the position of the favicon or alert
// indicator for pinned tabs. The visual_width parameter is how wide the
// icon looks (rather than how wide the bounds are).
......@@ -252,9 +252,9 @@ class Tab : public gfx::AnimationDelegate,
bool active,
SkColor color);
// Paints the separator line on the left edge of the tab if in material
// refresh mode.
void PaintSeparator(gfx::Canvas* canvas);
// Paints the separator lines on the left and right edge of the tab if in
// material refresh mode.
void PaintSeparators(gfx::Canvas* canvas);
// Computes which icons are visible in the tab. Should be called everytime
// before layout is performed.
......
......@@ -29,16 +29,17 @@ class View;
// Controller for tabs.
class TabController {
public:
// Used in GetAdjacentTab to indicate which adjacent tab to retrieve. FORWARD
// will return the adjacent tab to the right. BACKWARD will return the
// adjacent tab to the left of the given tab.
enum Direction { FORWARD, BACKWARD };
virtual const ui::ListSelectionModel& GetSelectionModel() const = 0;
// Returns true if multiple selection is supported.
virtual bool SupportsMultipleSelection() = 0;
// Under Refresh, returns where the new tab button should be placed. This is
// needed to determine which tab separators need to be faded in/out while
// animating into position.
virtual NewTabButtonPosition GetNewTabButtonPosition() const = 0;
// Returns true if the close button for the given tab is forced to be hidden.
virtual bool ShouldHideCloseButtonForTab(Tab* tab) const = 0;
......@@ -83,6 +84,10 @@ class TabController {
// Returns true if the specified Tab is pinned.
virtual bool IsTabPinned(const Tab* tab) const = 0;
// Returns true if the specified tab is the first or last one visible.
virtual bool IsFirstVisibleTab(const Tab* tab) const = 0;
virtual bool IsLastVisibleTab(const Tab* tab) const = 0;
// Returns true if the tab is a part of an incognito profile.
virtual bool IsIncognito() const = 0;
......@@ -104,9 +109,9 @@ class TabController {
virtual Tab* GetTabAt(Tab* tab,
const gfx::Point& tab_in_tab_coordinates) = 0;
// Returns the next/previous tab in the model order. Returns nullptr if there
// isn't an adjacent tab in the given direction.
virtual Tab* GetAdjacentTab(Tab* tab, Direction direction) = 0;
// Returns the next tab in the model order. Returns nullptr if there
// isn't another tab beyond the given tab.
virtual Tab* GetSubsequentTab(Tab* tab) = 0;
// Invoked when a mouse event occurs on |source|.
virtual void OnMouseEventInTab(views::View* source,
......@@ -149,6 +154,11 @@ class TabController {
// background images have been customized; see implementation comments.
virtual int GetBackgroundResourceId(bool* custom_image) const = 0;
// If the given tab is animating to its target destination, this returns the
// target bounds. If the tab isn't moving this will return the current bounds
// of the given tab.
virtual gfx::Rect GetTabAnimationTargetBounds(Tab* tab) = 0;
// Returns the accessible tab name for this tab.
virtual base::string16 GetAccessibleTabName(const Tab* tab) const = 0;
......
......@@ -831,6 +831,10 @@ bool TabStrip::SupportsMultipleSelection() {
return touch_layout_ == nullptr;
}
NewTabButtonPosition TabStrip::GetNewTabButtonPosition() const {
return controller_->GetNewTabButtonPosition();
}
bool TabStrip::ShouldHideCloseButtonForTab(Tab* tab) const {
if (tab->IsActive())
return SingleTabMode();
......@@ -918,6 +922,14 @@ bool TabStrip::IsTabPinned(const Tab* tab) const {
controller_->IsTabPinned(model_index);
}
bool TabStrip::IsFirstVisibleTab(const Tab* tab) const {
return GetModelIndexOfTab(tab) == 0;
}
bool TabStrip::IsLastVisibleTab(const Tab* tab) const {
return GetLastVisibleTab() == tab;
}
bool TabStrip::IsIncognito() const {
// There may be no controller in tests.
return controller_ && controller_->IsIncognito();
......@@ -1019,13 +1031,12 @@ Tab* TabStrip::GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) {
return view && view->id() == VIEW_ID_TAB ? static_cast<Tab*>(view) : nullptr;
}
Tab* TabStrip::GetAdjacentTab(Tab* tab, TabController::Direction direction) {
const int index = GetModelIndexOfTab(tab);
Tab* TabStrip::GetSubsequentTab(Tab* tab) {
int index = GetModelIndexOfTab(tab);
if (index < 0)
return nullptr;
const int new_index = index + (direction == TabController::FORWARD ? 1 : -1);
return new_index < 0 || new_index >= tab_count() ? nullptr
: tab_at(new_index);
++index;
return index >= tab_count() ? nullptr : tab_at(index);
}
void TabStrip::OnMouseEventInTab(views::View* source,
......@@ -1133,6 +1144,10 @@ int TabStrip::GetBackgroundResourceId(bool* custom_image) const {
return id;
}
gfx::Rect TabStrip::GetTabAnimationTargetBounds(Tab* tab) {
return bounds_animator_.GetTargetBounds(tab);
}
void TabStrip::MouseMovedOutOfHost() {
ResizeLayoutTabs();
if (reset_to_shrink_on_exit_) {
......@@ -1283,6 +1298,20 @@ void TabStrip::PaintChildren(const views::PaintInfo& paint_info) {
}
}
void TabStrip::OnPaint(gfx::Canvas* canvas) {
views::View::OnPaint(canvas);
if (MD::IsRefreshUi() && GetNewTabButtonPosition() == TRAILING) {
float separator_height = Tab::GetTabSeparatorHeight();
gfx::RectF separator_bounds(
new_tab_button_bounds_.x() - Tab::GetOverlap() / 2,
(height() - separator_height) / 2, 1, separator_height);
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setColor(GetTabSeparatorColor());
canvas->DrawRect(separator_bounds, flags);
}
}
const char* TabStrip::GetClassName() const {
static const char kViewClassName[] = "TabStrip";
return kViewClassName;
......
......@@ -229,6 +229,7 @@ class TabStrip : public views::View,
// TabController:
const ui::ListSelectionModel& GetSelectionModel() const override;
bool SupportsMultipleSelection() override;
NewTabButtonPosition GetNewTabButtonPosition() const override;
bool ShouldHideCloseButtonForTab(Tab* tab) const override;
bool ShouldShowCloseButtonOnHover() override;
bool MaySetClip() override;
......@@ -244,6 +245,8 @@ class TabStrip : public views::View,
bool IsActiveTab(const Tab* tab) const override;
bool IsTabSelected(const Tab* tab) const override;
bool IsTabPinned(const Tab* tab) const override;
bool IsFirstVisibleTab(const Tab* tab) const override;
bool IsLastVisibleTab(const Tab* tab) const override;
bool IsIncognito() const override;
void MaybeStartDrag(
Tab* tab,
......@@ -252,7 +255,7 @@ class TabStrip : public views::View,
void ContinueDrag(views::View* view, const ui::LocatedEvent& event) override;
bool EndDrag(EndDragReason reason) override;
Tab* GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) override;
Tab* GetAdjacentTab(Tab* tab, TabController::Direction direction) override;
Tab* GetSubsequentTab(Tab* tab) override;
void OnMouseEventInTab(views::View* source,
const ui::MouseEvent& event) override;
bool ShouldPaintTab(
......@@ -267,6 +270,7 @@ class TabStrip : public views::View,
SkColor GetTabForegroundColor(TabState state) const override;
base::string16 GetAccessibleTabName(const Tab* tab) const override;
int GetBackgroundResourceId(bool* custom_image) const override;
gfx::Rect GetTabAnimationTargetBounds(Tab* tab) override;
// MouseWatcherListener:
void MouseMovedOutOfHost() override;
......@@ -274,6 +278,7 @@ class TabStrip : public views::View,
// views::View:
void Layout() override;
void PaintChildren(const views::PaintInfo& paint_info) override;
void OnPaint(gfx::Canvas* canvas) override;
const char* GetClassName() const override;
gfx::Size CalculatePreferredSize() const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
......
......@@ -39,6 +39,9 @@ class FakeTabController : public TabController {
return selection_model_;
}
bool SupportsMultipleSelection() override { return false; }
NewTabButtonPosition GetNewTabButtonPosition() const override {
return LEADING;
}
bool ShouldHideCloseButtonForTab(Tab* tab) const override { return false; }
bool ShouldShowCloseButtonOnHover() override { return false; }
bool MaySetClip() override { return false; }
......@@ -54,6 +57,8 @@ class FakeTabController : public TabController {
bool IsActiveTab(const Tab* tab) const override { return active_tab_; }
bool IsTabSelected(const Tab* tab) const override { return false; }
bool IsTabPinned(const Tab* tab) const override { return false; }
bool IsFirstVisibleTab(const Tab* tab) const override { return false; }
bool IsLastVisibleTab(const Tab* tab) const override { return false; }
bool IsIncognito() const override { return false; }
void MaybeStartDrag(
Tab* tab,
......@@ -65,9 +70,7 @@ class FakeTabController : public TabController {
Tab* GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) override {
return nullptr;
}
Tab* GetAdjacentTab(Tab* tab, TabController::Direction direction) override {
return nullptr;
}
Tab* GetSubsequentTab(Tab* tab) override { return nullptr; }
void OnMouseEventInTab(views::View* source,
const ui::MouseEvent& event) override {}
bool ShouldPaintTab(
......@@ -92,6 +95,9 @@ class FakeTabController : public TabController {
*custom_image = false;
return IDR_THEME_TAB_BACKGROUND;
}
gfx::Rect GetTabAnimationTargetBounds(Tab* tab) override {
return tab->bounds();
}
base::string16 GetAccessibleTabName(const Tab* tab) const override {
return base::string16();
}
......
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