Commit 4e963b73 authored by mad@chromium.org's avatar mad@chromium.org

Improvements to tab title prefix eliding as per email discussions.

- Don't look for common title prefixes between pages from different hosts.

- Bring down the minimal width of a tab title area from 10 to 6 chars.

- Don't elide last 4 chars of the common prefix, and also don't elide if there is less than 7 common characters.

BUG=None
TEST=Try it!
Review URL: http://codereview.chromium.org/6783015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80492 0039d316-1c4b-4281-b951-d872f2087c98
parent 97e780da
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "chrome/browser/ui/cocoa/hover_close_button.h" #import "chrome/browser/ui/cocoa/hover_close_button.h"
#include "chrome/browser/ui/tabs/tab_menu_model.h" #include "chrome/browser/ui/tabs/tab_menu_model.h"
#include "googleurl/src/gurl.h"
// The loading/waiting state of the tab. // The loading/waiting state of the tab.
enum TabLoadingState { enum TabLoadingState {
...@@ -49,6 +50,7 @@ class MenuDelegate; ...@@ -49,6 +50,7 @@ class MenuDelegate;
BOOL mini_; BOOL mini_;
BOOL pinned_; BOOL pinned_;
BOOL selected_; BOOL selected_;
GURL url_;
TabLoadingState loadingState_; TabLoadingState loadingState_;
CGFloat iconTitleXOffset_; // between left edges of icon and title CGFloat iconTitleXOffset_; // between left edges of icon and title
id<TabControllerTarget> target_; // weak, where actions are sent id<TabControllerTarget> target_; // weak, where actions are sent
...@@ -66,6 +68,7 @@ class MenuDelegate; ...@@ -66,6 +68,7 @@ class MenuDelegate;
@property(assign, nonatomic) BOOL pinned; @property(assign, nonatomic) BOOL pinned;
@property(assign, nonatomic) BOOL selected; @property(assign, nonatomic) BOOL selected;
@property(assign, nonatomic) id target; @property(assign, nonatomic) id target;
@property(assign, nonatomic) GURL url;
@property(assign, nonatomic) NSView* iconView; @property(assign, nonatomic) NSView* iconView;
@property(assign, nonatomic) NSTextField* titleView; @property(assign, nonatomic) NSTextField* titleView;
@property(assign, nonatomic) HoverCloseButton* closeButton; @property(assign, nonatomic) HoverCloseButton* closeButton;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h" #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
#import "chrome/browser/ui/cocoa/tabs/tab_view.h" #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
#import "chrome/browser/ui/cocoa/themed_window.h" #import "chrome/browser/ui/cocoa/themed_window.h"
#include "chrome/browser/ui/title_prefix_matcher.h"
#import "chrome/common/extensions/extension.h" #import "chrome/common/extensions/extension.h"
#include "grit/generated_resources.h" #include "grit/generated_resources.h"
#import "third_party/GTM/AppKit/GTMFadeTruncatingTextFieldCell.h" #import "third_party/GTM/AppKit/GTMFadeTruncatingTextFieldCell.h"
...@@ -22,6 +23,7 @@ ...@@ -22,6 +23,7 @@
@synthesize mini = mini_; @synthesize mini = mini_;
@synthesize pinned = pinned_; @synthesize pinned = pinned_;
@synthesize target = target_; @synthesize target = target_;
@synthesize url = url_;
@synthesize iconView = iconView_; @synthesize iconView = iconView_;
@synthesize titleView = titleView_; @synthesize titleView = titleView_;
@synthesize closeButton = closeButton_; @synthesize closeButton = closeButton_;
...@@ -308,9 +310,10 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate { ...@@ -308,9 +310,10 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
DCHECK([[titleView_ cell] isKindOfClass: DCHECK([[titleView_ cell] isKindOfClass:
[GTMFadeTruncatingTextFieldCell class]]); [GTMFadeTruncatingTextFieldCell class]]);
GTMFadeTruncatingTextFieldCell* cell = [titleView_ cell]; GTMFadeTruncatingTextFieldCell* cell = [titleView_ cell];
[cell setDesiredCharactersToTruncateFromHead:length]; [cell setDesiredCharactersToTruncateFromHead:length -
[cell setTruncateMode:length > 0 ? GTMFadeTruncatingHeadAndTail : TitlePrefixMatcher::kCommonCharsToShow];
GTMFadeTruncatingTail]; [cell setTruncateMode:length > TitlePrefixMatcher::kMinElidingLength ?
GTMFadeTruncatingHeadAndTail : GTMFadeTruncatingTail];
} }
@end @end
...@@ -1104,6 +1104,7 @@ class NotificationBridge : public NotificationObserver { ...@@ -1104,6 +1104,7 @@ class NotificationBridge : public NotificationObserver {
[newController setMini:tabStripModel_->IsMiniTab(modelIndex)]; [newController setMini:tabStripModel_->IsMiniTab(modelIndex)];
[newController setPinned:tabStripModel_->IsTabPinned(modelIndex)]; [newController setPinned:tabStripModel_->IsTabPinned(modelIndex)];
[newController setApp:tabStripModel_->IsAppTab(modelIndex)]; [newController setApp:tabStripModel_->IsAppTab(modelIndex)];
[newController setUrl:contents->tab_contents()->GetURL()];
[tabArray_ insertObject:newController atIndex:index]; [tabArray_ insertObject:newController atIndex:index];
NSView* newView = [newController view]; NSView* newView = [newController view];
...@@ -1501,6 +1502,7 @@ class NotificationBridge : public NotificationObserver { ...@@ -1501,6 +1502,7 @@ class NotificationBridge : public NotificationObserver {
[tabController setMini:tabStripModel_->IsMiniTab(modelIndex)]; [tabController setMini:tabStripModel_->IsMiniTab(modelIndex)];
[tabController setPinned:tabStripModel_->IsTabPinned(modelIndex)]; [tabController setPinned:tabStripModel_->IsTabPinned(modelIndex)];
[tabController setApp:tabStripModel_->IsAppTab(modelIndex)]; [tabController setApp:tabStripModel_->IsAppTab(modelIndex)];
[tabController setUrl:contents->tab_contents()->GetURL()];
[self updateFaviconForContents:contents->tab_contents() atIndex:modelIndex]; [self updateFaviconForContents:contents->tab_contents() atIndex:modelIndex];
// If the tab is being restored and it's pinned, the mini state is set after // If the tab is being restored and it's pinned, the mini state is set after
// the tab has already been rendered, so re-layout the tabstrip. In all other // the tab has already been rendered, so re-layout the tabstrip. In all other
...@@ -2043,7 +2045,7 @@ class NotificationBridge : public NotificationObserver { ...@@ -2043,7 +2045,7 @@ class NotificationBridge : public NotificationObserver {
if (!title.empty() && ![tabController mini]) { if (!title.empty() && ![tabController mini]) {
titles.push_back(new string16(title)); titles.push_back(new string16(title));
tabTitleInfos.push_back(TitlePrefixMatcher::TitleInfo( tabTitleInfos.push_back(TitlePrefixMatcher::TitleInfo(
titles[titles.size() - 1], tabIndex)); titles[titles.size() - 1], [tabController url], tabIndex));
} }
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/hash_tables.h" #include "base/hash_tables.h"
#include "base/i18n/break_iterator.h" #include "base/i18n/break_iterator.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/utf_string_conversions.h"
namespace { namespace {
// We use this value to identify that we have already seen the title associated // We use this value to identify that we have already seen the title associated
...@@ -14,14 +15,23 @@ namespace { ...@@ -14,14 +15,23 @@ namespace {
const size_t kPreviouslySeenIndex = 0xFFFFFFFF; const size_t kPreviouslySeenIndex = 0xFFFFFFFF;
} }
TitlePrefixMatcher::TitleInfo::TitleInfo(const string16* title, // static
int caller_value) const int TitlePrefixMatcher::kCommonCharsToShow = 4;
const size_t TitlePrefixMatcher::kMinElidingLength =
TitlePrefixMatcher::kCommonCharsToShow + 3;
TitlePrefixMatcher::TitleInfo::TitleInfo(
const string16* title, const GURL& url, int caller_value)
: title(title), : title(title),
url(url),
prefix_length(0), prefix_length(0),
caller_value(caller_value) { caller_value(caller_value) {
DCHECK(title != NULL); DCHECK(title != NULL);
} }
TitlePrefixMatcher::TitleInfo::~TitleInfo() {
}
// static // static
void TitlePrefixMatcher::CalculatePrefixLengths( void TitlePrefixMatcher::CalculatePrefixLengths(
std::vector<TitleInfo>* title_infos) { std::vector<TitleInfo>* title_infos) {
...@@ -41,12 +51,12 @@ void TitlePrefixMatcher::CalculatePrefixLengths( ...@@ -41,12 +51,12 @@ void TitlePrefixMatcher::CalculatePrefixLengths(
for (size_t i = 0; i < title_infos->size(); ++i) { for (size_t i = 0; i < title_infos->size(); ++i) {
// We use pairs to test existence and insert in one shot. // We use pairs to test existence and insert in one shot.
std::pair<base::hash_map<string16, size_t>::iterator, bool> insert_result = std::pair<base::hash_map<string16, size_t>::iterator, bool> insert_result =
existing_title.insert(std::make_pair(*title_infos->at(i).title, i)); existing_title.insert(std::make_pair(*(*title_infos)[i].title, i));
if (!insert_result.second) { if (!insert_result.second) {
// insert_result.second is false when we insert a duplicate in the set. // insert_result.second is false when we insert a duplicate in the set.
// insert_result.first is a map iterator and thus // insert_result.first is a map iterator and thus
// insert_result.first->first is the string title key of the map. // insert_result.first->first is the string title key of the map.
DCHECK(*title_infos->at(i).title == insert_result.first->first); DCHECK_EQ(*(*title_infos)[i].title, insert_result.first->first);
duplicate_titles.insert(i); duplicate_titles.insert(i);
// insert_result.first->second is the value of the title index and if it's // insert_result.first->second is the value of the title index and if it's
// not kPreviouslySeenIndex yet, we must remember it as a duplicate too. // not kPreviouslySeenIndex yet, we must remember it as a duplicate too.
...@@ -64,7 +74,11 @@ void TitlePrefixMatcher::CalculatePrefixLengths( ...@@ -64,7 +74,11 @@ void TitlePrefixMatcher::CalculatePrefixLengths(
// Duplicate titles are not to be included in this process. // Duplicate titles are not to be included in this process.
if (duplicate_titles.find(i) != duplicate_titles.end()) if (duplicate_titles.find(i) != duplicate_titles.end())
continue; continue;
const string16* title = title_infos->at(i).title; const TitleInfo& title_info = (*title_infos)[i];
const string16* title = title_info.title;
// We prefix the hostname at the beginning, so that we only group
// titles that are from the same hostname.
string16 hostname = ASCIIToUTF16(title_info.url.host());
// We only create prefixes at word boundaries. // We only create prefixes at word boundaries.
base::BreakIterator iter(title, base::BreakIterator::BREAK_WORD); base::BreakIterator iter(title, base::BreakIterator::BREAK_WORD);
// We ignore this title if we can't break it into words, or if it only // We ignore this title if we can't break it into words, or if it only
...@@ -76,7 +90,7 @@ void TitlePrefixMatcher::CalculatePrefixLengths( ...@@ -76,7 +90,7 @@ void TitlePrefixMatcher::CalculatePrefixLengths(
// previous word and more easily ignore the last word while iterating. // previous word and more easily ignore the last word while iterating.
while (iter.Advance()) { while (iter.Advance()) {
if (iter.IsWord()) if (iter.IsWord())
prefixes[title->substr(0, iter.prev())].push_back(i); prefixes[hostname + title->substr(0, iter.prev())].push_back(i);
} }
} }
...@@ -86,10 +100,16 @@ void TitlePrefixMatcher::CalculatePrefixLengths( ...@@ -86,10 +100,16 @@ void TitlePrefixMatcher::CalculatePrefixLengths(
prefixes.begin(); iter != prefixes.end(); ++iter) { prefixes.begin(); iter != prefixes.end(); ++iter) {
// iter->first is the prefix string, iter->second is a vector of indices. // iter->first is the prefix string, iter->second is a vector of indices.
if (iter->second.size() > 1) { if (iter->second.size() > 1) {
size_t prefix_length = iter->first.size(); // We need to subtract the hostname size since we added it to the prefix.
const TitleInfo& first_title_info = (*title_infos)[iter->second[0]];
DCHECK_GE(iter->first.size(), first_title_info.url.host().size());
size_t prefix_length = iter->first.size() -
first_title_info.url.host().size();
for (size_t i = 0; i < iter->second.size(); ++i){ for (size_t i = 0; i < iter->second.size(); ++i){
if (title_infos->at(iter->second[i]).prefix_length < prefix_length) TitleInfo& title_info = (*title_infos)[iter->second[i]];
title_infos->at(iter->second[i]).prefix_length = prefix_length; DCHECK_EQ(first_title_info.url.host(), title_info.url.host());
if (title_info.prefix_length < prefix_length)
title_info.prefix_length = prefix_length;
} }
} }
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "base/string16.h" #include "base/string16.h"
#include "googleurl/src/gurl.h"
// This class exposes a static method that receives a vector of TitleInfo // This class exposes a static method that receives a vector of TitleInfo
// objects so that it can find the length of the common prefixes among all // objects so that it can find the length of the common prefixes among all
...@@ -26,11 +27,14 @@ ...@@ -26,11 +27,14 @@
class TitlePrefixMatcher { class TitlePrefixMatcher {
public: public:
struct TitleInfo { struct TitleInfo {
TitleInfo(const string16* title, int caller_value); TitleInfo(const string16* title, const GURL& url, int caller_value);
~TitleInfo();
// We assume the title string will be valid throughout the execution of // We assume the title string will be valid throughout the execution of
// the prefix lengths calculation, and so we use a pointer to avoid an // the prefix lengths calculation, and so we use a pointer to avoid an
// unnecessary string copy. // unnecessary string copy.
const string16* title; const string16* title;
// We only look for common prefix when the URL has the same hostname.
GURL url;
// This contains the number of characters at the beginning of title that // This contains the number of characters at the beginning of title that
// are common with other titles in the TitleInfo vector. // are common with other titles in the TitleInfo vector.
size_t prefix_length; size_t prefix_length;
...@@ -39,6 +43,12 @@ class TitlePrefixMatcher { ...@@ -39,6 +43,12 @@ class TitlePrefixMatcher {
}; };
static void CalculatePrefixLengths(std::vector<TitleInfo>* title_infos); static void CalculatePrefixLengths(std::vector<TitleInfo>* title_infos);
// We want to show the last few common chars of a page title in the tab,
// so we only do it if the common prefix is at least kMinElidingLength,
// otherwise, we could be replacing less characters than the ellipsis take.
static const int kCommonCharsToShow;
static const size_t kMinElidingLength;
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(TitlePrefixMatcher); DISALLOW_IMPLICIT_CONSTRUCTORS(TitlePrefixMatcher);
}; };
......
...@@ -5,10 +5,15 @@ ...@@ -5,10 +5,15 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "chrome/browser/ui/title_prefix_matcher.h" #include "chrome/browser/ui/title_prefix_matcher.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace { namespace {
const GURL kUrlA1("http://a.b.c/123");
const GURL kUrlA2("http://a.b.c/alphabits");
const GURL kUrlB1("http://www.here.com/here/and/there");
const GURL kUrlB2("http://www.here.com/elsewhere");
const GURL kUrlC1("http://www.here.ca/far/far/away");
const string16 kFoofooAbcdef(ASCIIToUTF16("Foofoo abcdef")); const string16 kFoofooAbcdef(ASCIIToUTF16("Foofoo abcdef"));
const string16 kFoofooAbcdeg(ASCIIToUTF16("Foofoo abcdeg")); const string16 kFoofooAbcdeg(ASCIIToUTF16("Foofoo abcdeg"));
const string16 kFooAbcdef(ASCIIToUTF16("Foo abcdef")); const string16 kFooAbcdef(ASCIIToUTF16("Foo abcdef"));
...@@ -23,8 +28,10 @@ const string16 kFoo(ASCIIToUTF16("Foo")); ...@@ -23,8 +28,10 @@ const string16 kFoo(ASCIIToUTF16("Foo"));
TEST(TitlePrefixMatcherTest, BasicTests) { TEST(TitlePrefixMatcherTest, BasicTests) {
std::vector<TitlePrefixMatcher::TitleInfo> tab_title_infos; std::vector<TitlePrefixMatcher::TitleInfo> tab_title_infos;
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef, 0)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef,
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdeg, 1)); kUrlA1, 0));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdeg,
kUrlA1, 1));
TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos); TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos);
EXPECT_EQ(0, tab_title_infos[0].caller_value); EXPECT_EQ(0, tab_title_infos[0].caller_value);
...@@ -34,10 +41,14 @@ TEST(TitlePrefixMatcherTest, BasicTests) { ...@@ -34,10 +41,14 @@ TEST(TitlePrefixMatcherTest, BasicTests) {
EXPECT_EQ(7U, tab_title_infos[1].prefix_length); EXPECT_EQ(7U, tab_title_infos[1].prefix_length);
tab_title_infos.clear(); tab_title_infos.clear();
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef, 0)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef,
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdeg, 1)); kUrlA1, 0));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdef, 2)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdeg,
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdeg, 3)); kUrlA1, 1));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdef,
kUrlA1, 2));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdeg,
kUrlA1, 3));
TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos); TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos);
EXPECT_EQ(0, tab_title_infos[0].caller_value); EXPECT_EQ(0, tab_title_infos[0].caller_value);
...@@ -55,11 +66,16 @@ TEST(TitlePrefixMatcherTest, BasicTests) { ...@@ -55,11 +66,16 @@ TEST(TitlePrefixMatcherTest, BasicTests) {
TEST(TitlePrefixMatcherTest, Duplicates) { TEST(TitlePrefixMatcherTest, Duplicates) {
std::vector<TitlePrefixMatcher::TitleInfo> tab_title_infos; std::vector<TitlePrefixMatcher::TitleInfo> tab_title_infos;
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef, 0)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef,
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdeg, 1)); kUrlA1, 0));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdef, 2)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdeg,
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdeg, 3)); kUrlA1, 1));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef, 4)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdef,
kUrlA1, 2));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdeg,
kUrlA1, 3));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef,
kUrlA1, 4));
TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos); TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos);
EXPECT_EQ(0, tab_title_infos[0].caller_value); EXPECT_EQ(0, tab_title_infos[0].caller_value);
...@@ -80,13 +96,20 @@ TEST(TitlePrefixMatcherTest, Duplicates) { ...@@ -80,13 +96,20 @@ TEST(TitlePrefixMatcherTest, Duplicates) {
TEST(TitlePrefixMatcherTest, MultiplePrefixes) { TEST(TitlePrefixMatcherTest, MultiplePrefixes) {
std::vector<TitlePrefixMatcher::TitleInfo> tab_title_infos; std::vector<TitlePrefixMatcher::TitleInfo> tab_title_infos;
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdef, 0)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdef,
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdeg, 1)); kUrlA1, 0));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbcDef, 2)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdeg,
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbcDeg, 3)); kUrlA1, 1));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbdDef, 4)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbcDef,
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBar, 5)); kUrlA1, 2));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoo, 6)); tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbcDeg,
kUrlA1, 3));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbdDef,
kUrlA1, 4));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBar,
kUrlA1, 5));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoo,
kUrlA1, 6));
TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos); TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos);
EXPECT_EQ(0, tab_title_infos[0].caller_value); EXPECT_EQ(0, tab_title_infos[0].caller_value);
...@@ -110,3 +133,43 @@ TEST(TitlePrefixMatcherTest, MultiplePrefixes) { ...@@ -110,3 +133,43 @@ TEST(TitlePrefixMatcherTest, MultiplePrefixes) {
EXPECT_EQ(6, tab_title_infos[6].caller_value); EXPECT_EQ(6, tab_title_infos[6].caller_value);
EXPECT_EQ(0U, tab_title_infos[6].prefix_length); EXPECT_EQ(0U, tab_title_infos[6].prefix_length);
} }
TEST(TitlePrefixMatcherTest, DifferentHosts) {
std::vector<TitlePrefixMatcher::TitleInfo> tab_title_infos;
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdef,
kUrlA1, 0));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFoofooAbcdeg,
kUrlA2, 1));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdef,
kUrlB1, 2));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbdDef,
kUrlC1, 3));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbcDef,
kUrlA1, 4));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kBarAbcDeg,
kUrlA2, 5));
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(&kFooAbcdeg,
kUrlB2, 6));
TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos);
EXPECT_EQ(0, tab_title_infos[0].caller_value);
EXPECT_EQ(7U, tab_title_infos[0].prefix_length);
EXPECT_EQ(1, tab_title_infos[1].caller_value);
EXPECT_EQ(7U, tab_title_infos[1].prefix_length);
EXPECT_EQ(2, tab_title_infos[2].caller_value);
EXPECT_EQ(4U, tab_title_infos[2].prefix_length);
EXPECT_EQ(3, tab_title_infos[3].caller_value);
EXPECT_EQ(0U, tab_title_infos[3].prefix_length);
EXPECT_EQ(4, tab_title_infos[4].caller_value);
EXPECT_EQ(8U, tab_title_infos[4].prefix_length);
EXPECT_EQ(5, tab_title_infos[5].caller_value);
EXPECT_EQ(8U, tab_title_infos[5].prefix_length);
EXPECT_EQ(6, tab_title_infos[6].caller_value);
EXPECT_EQ(4U, tab_title_infos[6].prefix_length);
}
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/ui/title_prefix_matcher.h"
#include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/tabs/tab_controller.h" #include "chrome/browser/ui/views/tabs/tab_controller.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
...@@ -479,11 +480,14 @@ void BaseTab::PaintTitle(gfx::Canvas* canvas, SkColor title_color) { ...@@ -479,11 +480,14 @@ void BaseTab::PaintTitle(gfx::Canvas* canvas, SkColor title_color) {
Browser::FormatTitleForDisplay(&title); Browser::FormatTitleForDisplay(&title);
// If we'll need to truncate, check if we should also truncate // If we'll need to truncate, check if we should also truncate
// a common prefix, but only if there is enough room for it. // a common prefix, but only if there is enough room for it.
// We arbitrarily choose to request enough room for 10 average chars. // We arbitrarily choose to request enough room for 6 average chars.
if (data().common_prefix_length > 0 && if (data().common_prefix_length > TitlePrefixMatcher::kMinElidingLength &&
font_->GetExpectedTextWidth(10) < title_bounds.width() && font_->GetExpectedTextWidth(6) < title_bounds.width() &&
font_->GetStringWidth(title) > title_bounds.width()) { font_->GetStringWidth(title) > title_bounds.width()) {
title.replace(0, data().common_prefix_length, UTF8ToUTF16(ui::kEllipsis)); title.replace(0,
data().common_prefix_length -
TitlePrefixMatcher::kCommonCharsToShow,
UTF8ToUTF16(ui::kEllipsis));
} }
} }
canvas->DrawStringInt(title, *font_, title_color, canvas->DrawStringInt(title, *font_, title_color,
......
...@@ -476,7 +476,9 @@ void BaseTabStrip::UpdateCommonTitlePrefix() { ...@@ -476,7 +476,9 @@ void BaseTabStrip::UpdateCommonTitlePrefix() {
DCHECK(tab_data_[tab_index].tab != NULL); DCHECK(tab_data_[tab_index].tab != NULL);
if (!IgnoreTitlePrefixEliding(tab_data_[tab_index].tab)) { if (!IgnoreTitlePrefixEliding(tab_data_[tab_index].tab)) {
tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo( tab_title_infos.push_back(TitlePrefixMatcher::TitleInfo(
&tab_data_[tab_index].tab->data().title, tab_index)); &tab_data_[tab_index].tab->data().title,
tab_data_[tab_index].tab->data().url,
tab_index));
} }
} }
TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos); TitlePrefixMatcher::CalculatePrefixLengths(&tab_title_infos);
......
...@@ -403,6 +403,7 @@ void BrowserTabStripController::SetTabRendererDataFromModel( ...@@ -403,6 +403,7 @@ void BrowserTabStripController::SetTabRendererDataFromModel(
data->favicon = contents->GetFavicon(); data->favicon = contents->GetFavicon();
data->network_state = TabContentsNetworkState(contents); data->network_state = TabContentsNetworkState(contents);
data->title = contents->GetTitle(); data->title = contents->GetTitle();
data->url = contents->GetURL();
data->loading = contents->is_loading(); data->loading = contents->is_loading();
data->crashed_status = contents->crashed_status(); data->crashed_status = contents->crashed_status();
data->incognito = contents->profile()->IsOffTheRecord(); data->incognito = contents->profile()->IsOffTheRecord();
......
...@@ -25,6 +25,7 @@ bool TabRendererData::Equals(const TabRendererData& data) { ...@@ -25,6 +25,7 @@ bool TabRendererData::Equals(const TabRendererData& data) {
favicon.pixelRefOffset() == data.favicon.pixelRefOffset() && favicon.pixelRefOffset() == data.favicon.pixelRefOffset() &&
network_state == data.network_state && network_state == data.network_state &&
title == data.title && title == data.title &&
url == data.url &&
common_prefix_length == data.common_prefix_length && common_prefix_length == data.common_prefix_length &&
loading == data.loading && loading == data.loading &&
crashed_status == data.crashed_status && crashed_status == data.crashed_status &&
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/process_util.h" #include "base/process_util.h"
#include "base/string16.h" #include "base/string16.h"
#include "googleurl/src/gurl.h"
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkBitmap.h"
// Wraps the state needed by the renderers. // Wraps the state needed by the renderers.
...@@ -40,6 +41,7 @@ struct TabRendererData { ...@@ -40,6 +41,7 @@ struct TabRendererData {
SkBitmap favicon; SkBitmap favicon;
NetworkState network_state; NetworkState network_state;
string16 title; string16 title;
GURL url;
// Identifies the number of chars at the beginning of the string // Identifies the number of chars at the beginning of the string
// that are common to other tab titles. // that are common to other tab titles.
size_t common_prefix_length; size_t common_prefix_length;
......
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