blob: 9ffd03275f0a3a81df25df3bb9d60731ba22d372 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/tabs/tab_strip_layout.h"
#include <stddef.h>
#include <algorithm>
#include "base/logging.h"
#include "ui/gfx/geometry/rect.h"
namespace {
// Calculates the size for normal tabs.
// |is_active_tab_normal| is true if the active tab is a normal tab, if false
// the active tab is not in the set of normal tabs.
// |normal_width| is the available width for normal tabs.
void CalculateNormalTabWidths(const TabSizeInfo& tab_size_info,
bool is_active_tab_normal,
int num_normal_tabs,
int normal_width,
int* active_width,
int* inactive_width) {
DCHECK_NE(0, num_normal_tabs);
// Calculate the desired tab width by dividing the available space into equal
// portions, bounded by the standard width.
normal_width += tab_size_info.tab_overlap * (num_normal_tabs - 1);
int desired_tab_width = std::min(normal_width / num_normal_tabs,
tab_size_info.standard_size.width());
*active_width = std::max(desired_tab_width, tab_size_info.min_active_width);
// If |desired_tab_width| is smaller than the minimum active tab width, then
// we need to recalculate it having accounted for the active tab, since that
// may further shrink inactive tabs.
if ((*active_width > desired_tab_width) && is_active_tab_normal &&
(num_normal_tabs > 1))
desired_tab_width = (normal_width - *active_width) / (num_normal_tabs - 1);
*inactive_width =
std::max(desired_tab_width, tab_size_info.min_inactive_width);
}
} // namespace
int CalculateBoundsForPinnedTabs(const TabSizeInfo& tab_size_info,
int num_pinned_tabs,
int num_tabs,
int start_x,
std::vector<gfx::Rect>* tabs_bounds) {
DCHECK_EQ(static_cast<size_t>(num_tabs), tabs_bounds->size());
int next_x = start_x;
const int tab_height = tab_size_info.standard_size.height();
for (int index = 0; index < num_pinned_tabs; ++index) {
(*tabs_bounds)[index].SetRect(next_x, 0, tab_size_info.pinned_tab_width,
tab_height);
next_x += tab_size_info.pinned_tab_width - tab_size_info.tab_overlap;
}
return next_x;
}
std::vector<gfx::Rect> CalculateBounds(const TabSizeInfo& tab_size_info,
int num_pinned_tabs,
int num_tabs,
int active_index,
int start_x,
int width,
int* active_width,
int* inactive_width) {
DCHECK_NE(0, num_tabs);
std::vector<gfx::Rect> tabs_bounds(num_tabs);
*active_width = *inactive_width = tab_size_info.standard_size.width();
int next_x = CalculateBoundsForPinnedTabs(tab_size_info, num_pinned_tabs,
num_tabs, start_x, &tabs_bounds);
if (num_pinned_tabs == num_tabs)
return tabs_bounds;
width -= next_x - start_x;
const bool is_active_tab_normal = active_index >= num_pinned_tabs;
const int num_normal_tabs = num_tabs - num_pinned_tabs;
CalculateNormalTabWidths(tab_size_info, is_active_tab_normal, num_normal_tabs,
width, active_width, inactive_width);
// As CalculateNormalTabWidths() calculates sizes using ints there may be a
// bit of extra space (due to the available width not being an integer
// multiple of these sizes). Give the extra space to the first tabs, and only
// give extra space to the active tab if it is the same size as the inactive
// tabs (the active tab may already be bigger).
int extra_space = 0;
bool widen_active = false;
if (*inactive_width != tab_size_info.standard_size.width()) {
widen_active = *active_width == *inactive_width;
const int tab_width =
(*inactive_width - tab_size_info.tab_overlap) * (num_normal_tabs - 1) +
(is_active_tab_normal ? *active_width : *inactive_width);
extra_space = width - tab_width;
}
// Convert the widths to bounds.
const int tab_height = tab_size_info.standard_size.height();
for (int i = num_pinned_tabs; i < num_tabs; ++i) {
const bool is_active = i == active_index;
int width = is_active ? *active_width : *inactive_width;
if (extra_space > 0 && (!is_active || widen_active)) {
++width;
--extra_space;
}
tabs_bounds[i].SetRect(next_x, 0, width, tab_height);
next_x += tabs_bounds[i].width() - tab_size_info.tab_overlap;
}
return tabs_bounds;
}