summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormsw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-12 07:41:47 +0000
committermsw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-12 07:41:47 +0000
commit5f751daa2ab57bee299526a9a25b2d692513bdd1 (patch)
tree13bbc9a853a7835d2c8fea1f74837b564ba98f8b
parent19c602f19f20eab4ad2a5ac015eb70b254ccedb0 (diff)
downloadchromium_src-5f751daa2ab57bee299526a9a25b2d692513bdd1.zip
chromium_src-5f751daa2ab57bee299526a9a25b2d692513bdd1.tar.gz
chromium_src-5f751daa2ab57bee299526a9a25b2d692513bdd1.tar.bz2
Reland: Use labels to display views tab titles.
The original r276450 was reverted in r276476 for leaks: http://build.chromium.org/p/chromium.memory/builders/Linux%20ASan%20LSan%20Tests%20%283%29/builds/3954 Fixed here by calling AddChildView(title_) on Tab (duh). Add a Label view to Tab for displaying the title. Remove Tab::PaintTitle, bounds and font members. Remove unnecessary Tab::Get[Title|Icon]Bounds helpers. Update the text on Tab::SetData, not during paint. Use gfx::DirectionalityMode, remove the Label enum. Add gfx::ALIGN_TO_HEAD to gfx::HorizontalAlignment. Add Label::GetHorizontalAlignment for ALIGN_TO_HEAD. Always flip left/right in Label::SetHorizontalAlignment. Have Tab and MessageBoxView use ALIGN_TO_HEAD. Update comments and tests, related minor cleanup. TODO: Make Label cache RenderText objects. TODO: Make RenderText support ALIGN_TO_HEAD. BUG=240037 TEST=No visible Views tab title changes. R=sky@chromium.org Review URL: https://codereview.chromium.org/329813003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276566 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/ui/views/tabs/tab.cc102
-rw-r--r--chrome/browser/ui/views/tabs/tab.h14
-rw-r--r--chrome/browser/ui/views/tabs/tab_unittest.cc17
-rw-r--r--chrome/browser/ui/views/validation_message_bubble_delegate.cc5
-rw-r--r--ui/gfx/text_constants.h1
-rw-r--r--ui/message_center/views/bounded_label.cc7
-rw-r--r--ui/views/controls/button/label_button.cc2
-rw-r--r--ui/views/controls/label.cc56
-rw-r--r--ui/views/controls/label.h59
-rw-r--r--ui/views/controls/label_unittest.cc122
-rw-r--r--ui/views/controls/message_box_view.cc14
11 files changed, 171 insertions, 228 deletions
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index ff64038..62e38d5 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -35,7 +35,6 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/favicon_size.h"
-#include "ui/gfx/font.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/path.h"
#include "ui/gfx/rect_conversions.h"
@@ -43,6 +42,7 @@
#include "ui/gfx/text_elider.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/label.h"
#include "ui/views/rect_based_targeting_utils.h"
#include "ui/views/widget/tooltip_manager.h"
#include "ui/views/widget/widget.h"
@@ -375,10 +375,6 @@ Tab::TabImage Tab::tab_alpha_ = {0};
Tab::TabImage Tab::tab_active_ = {0};
Tab::TabImage Tab::tab_inactive_ = {0};
// static
-gfx::Font* Tab::font_ = NULL;
-// static
-int Tab::font_height_ = 0;
-// static
Tab::ImageCache* Tab::image_cache_ = NULL;
////////////////////////////////////////////////////////////////////////////////
@@ -393,6 +389,8 @@ Tab::Tab(TabController* controller)
immersive_loading_step_(0),
should_display_crashed_favicon_(false),
animating_media_state_(TAB_MEDIA_STATE_NONE),
+ close_button_(NULL),
+ title_(new views::Label()),
tab_activated_with_last_gesture_begin_(false),
hover_controller_(this),
showing_icon_(false),
@@ -408,6 +406,11 @@ Tab::Tab(TabController* controller)
set_id(VIEW_ID_TAB);
+ title_->set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
+ title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
+ title_->SetElideBehavior(gfx::FADE_TAIL);
+ AddChildView(title_);
+
// Add the Close Button.
close_button_ = new TabCloseButton(this);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
@@ -450,6 +453,16 @@ void Tab::SetData(const TabRendererData& data) {
TabRendererData old(data_);
data_ = data;
+ base::string16 title = data_.title;
+ if (title.empty()) {
+ title = data_.loading ?
+ l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
+ CoreTabHelper::GetDefaultTitle();
+ } else {
+ Browser::FormatTitleForDisplay(&title);
+ }
+ title_->SetText(title);
+
if (data_.IsCrashed()) {
if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation()) {
data_.media_state = TAB_MEDIA_STATE_NONE;
@@ -686,7 +699,8 @@ void Tab::Layout() {
// The height of the content of the Tab is the largest of the favicon,
// the title text and the close button graphic.
const int kTabIconSize = gfx::kFaviconSize;
- int content_height = std::max(kTabIconSize, font_height_);
+ const int font_height = title_->font_list().GetHeight();
+ int content_height = std::max(kTabIconSize, font_height);
close_button_->SetBorder(views::Border::NullBorder());
gfx::Size close_button_size(close_button_->GetPreferredSize());
content_height = std::max(content_height, close_button_size.height());
@@ -758,14 +772,15 @@ void Tab::Layout() {
kTitleTextOffsetYAsh : kTitleTextOffsetY;
int title_left = favicon_bounds_.right() + kFaviconTitleSpacing;
int title_top = kTopPadding + title_text_offset +
- (content_height - font_height_) / 2;
+ (content_height - font_height) / 2;
+ gfx::Rect title_bounds(title_left, title_top, 0, 0);
// Size the Title text to fill the remaining space.
if (!data().mini || width() >= kMiniTabRendererAsNormalTabWidth) {
// If the user has big fonts, the title will appear rendered too far down
// on the y-axis if we use the regular top padding, so we need to adjust it
// so that the text appears centered.
gfx::Size minimum_size = GetMinimumUnselectedSize();
- int text_height = title_top + font_height_ + kBottomPadding;
+ int text_height = title_top + font_height + kBottomPadding;
if (text_height > minimum_size.height())
title_top -= (text_height - minimum_size.height()) / 2;
@@ -783,19 +798,11 @@ void Tab::Layout() {
title_width = lb.width() - title_left;
}
title_width = std::max(title_width, 0);
- title_bounds_.SetRect(title_left, title_top, title_width, font_height_);
- } else {
- title_bounds_.SetRect(title_left, title_top, 0, 0);
+ title_bounds.SetRect(title_left, title_top, title_width, font_height);
}
- // Certain UI elements within the Tab (the favicon, etc.) are not represented
- // as child Views (which is the preferred method). Instead, these UI elements
- // are drawn directly on the canvas from within Tab::OnPaint(). The Tab's
- // child Views (for example, the Tab's close button which is a views::Button
- // instance) are automatically mirrored by the mirroring infrastructure in
- // views. The elements Tab draws directly on the canvas need to be manually
- // mirrored if the View's layout is right-to-left.
- title_bounds_.set_x(GetMirroredXForRect(title_bounds_));
+ title_bounds.set_x(GetMirroredXForRect(title_bounds));
+ title_->SetBoundsRect(title_bounds);
}
void Tab::OnThemeChanged() {
@@ -840,7 +847,7 @@ bool Tab::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const {
}
bool Tab::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* origin) const {
- origin->set_x(title_bounds_.x() + 10);
+ origin->set_x(title_->x() + 10);
origin->set_y(-views::TooltipManager::GetTooltipHeight() - 4);
return true;
}
@@ -983,14 +990,6 @@ void Tab::GetAccessibleState(ui::AXViewState* state) {
////////////////////////////////////////////////////////////////////////////////
// Tab, private
-const gfx::Rect& Tab::GetTitleBounds() const {
- return title_bounds_;
-}
-
-const gfx::Rect& Tab::GetIconBounds() const {
- return favicon_bounds_;
-}
-
void Tab::MaybeAdjustLeftForMiniTab(gfx::Rect* bounds) const {
if (!data().mini || width() >= kMiniTabRendererAsNormalTabWidth)
return;
@@ -1028,13 +1027,13 @@ void Tab::PaintTab(gfx::Canvas* canvas) {
PaintTabBackground(canvas);
- SkColor title_color = GetThemeProvider()->
- GetColor(IsSelected() ?
- ThemeProperties::COLOR_TAB_TEXT :
- ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
-
- if (!data().mini || width() > kMiniTabRendererAsNormalTabWidth)
- PaintTitle(canvas, title_color);
+ const SkColor title_color = GetThemeProvider()->GetColor(IsSelected() ?
+ ThemeProperties::COLOR_TAB_TEXT :
+ ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
+ if (!data().mini || width() > kMiniTabRendererAsNormalTabWidth) {
+ title_->SetEnabledColor(title_color);
+ title_->Paint(canvas, views::CullSet());
+ }
if (show_icon)
PaintIcon(canvas);
@@ -1331,7 +1330,7 @@ void Tab::PaintActiveTabBackground(gfx::Canvas* canvas) {
}
void Tab::PaintIcon(gfx::Canvas* canvas) {
- gfx::Rect bounds = GetIconBounds();
+ gfx::Rect bounds = favicon_bounds_;
if (bounds.IsEmpty())
return;
@@ -1355,9 +1354,9 @@ void Tab::PaintIcon(gfx::Canvas* canvas) {
gfx::ImageSkia crashed_favicon(*rb.GetImageSkiaNamed(IDR_SAD_FAVICON));
bounds.set_y(bounds.y() + favicon_hiding_offset_);
DrawIconCenter(canvas, crashed_favicon, 0,
- crashed_favicon.width(),
- crashed_favicon.height(),
- bounds, true, SkPaint());
+ crashed_favicon.width(),
+ crashed_favicon.height(),
+ bounds, true, SkPaint());
} else if (!data().favicon.isNull()) {
// Paint the normal favicon.
DrawIconCenter(canvas, data().favicon, 0,
@@ -1389,21 +1388,6 @@ void Tab::PaintMediaIndicator(gfx::Canvas* canvas) {
media_indicator_image.height(), true, paint);
}
-void Tab::PaintTitle(gfx::Canvas* canvas, SkColor title_color) {
- // Paint the Title.
- base::string16 title = data().title;
- if (title.empty()) {
- title = data().loading ?
- l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
- CoreTabHelper::GetDefaultTitle();
- } else {
- Browser::FormatTitleForDisplay(&title);
- }
-
- canvas->DrawFadedString(title, gfx::FontList(*font_), title_color,
- GetTitleBounds(), 0);
-}
-
void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state,
TabRendererData::NetworkState state) {
static bool initialized = false;
@@ -1546,12 +1530,11 @@ void Tab::StartMediaIndicatorAnimation() {
}
void Tab::ScheduleIconPaint() {
- gfx::Rect bounds = GetIconBounds();
+ gfx::Rect bounds = favicon_bounds_;
if (bounds.IsEmpty())
return;
- // Extends the area to the bottom when sad_favicon is
- // animating.
+ // Extends the area to the bottom when sad_favicon is animating.
if (IsPerformingCrashAnimation())
bounds.set_height(height() - bounds.y());
bounds.set_x(GetMirroredXForRect(bounds));
@@ -1595,11 +1578,6 @@ void Tab::InitTabResources() {
return;
initialized = true;
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- font_ = new gfx::Font(rb.GetFont(ui::ResourceBundle::BaseFont));
- font_height_ = font_->GetHeight();
-
image_cache_ = new ImageCache();
// Load the tab images once now, and maybe again later if the theme changes.
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index d5b71cd..ab362b4 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -24,12 +24,12 @@ class TabController;
namespace gfx {
class Animation;
class AnimationContainer;
-class Font;
class LinearAnimation;
class MultiAnimation;
}
namespace views {
class ImageButton;
+class Label;
}
///////////////////////////////////////////////////////////////////////////////
@@ -185,10 +185,6 @@ class Tab : public gfx::AnimationDelegate,
// Overridden from ui::EventHandler:
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
- // Returns the bounds of the title and icon.
- const gfx::Rect& GetTitleBounds() const;
- const gfx::Rect& GetIconBounds() const;
-
// Invoked from Layout to adjust the position of the favicon or media
// indicator for mini tabs.
void MaybeAdjustLeftForMiniTab(gfx::Rect* bounds) const;
@@ -212,10 +208,9 @@ class Tab : public gfx::AnimationDelegate,
int tab_id);
void PaintActiveTabBackground(gfx::Canvas* canvas);
- // Paints the favicon, media indicator icon, etc., mirrored for RTL if needed.
+ // Paints the favicon and media indicator icon, mirrored for RTL if needed.
void PaintIcon(gfx::Canvas* canvas);
void PaintMediaIndicator(gfx::Canvas* canvas);
- void PaintTitle(gfx::Canvas* canvas, SkColor title_color);
// Invoked if data_.network_state changes, or the network_state is not none.
void AdvanceLoadingAnimation(TabRendererData::NetworkState old_state,
@@ -326,6 +321,7 @@ class Tab : public gfx::AnimationDelegate,
scoped_refptr<gfx::AnimationContainer> animation_container_;
views::ImageButton* close_button_;
+ views::Label* title_;
bool tab_activated_with_last_gesture_begin_;
@@ -333,7 +329,6 @@ class Tab : public gfx::AnimationDelegate,
// The bounds of various sections of the display.
gfx::Rect favicon_bounds_;
- gfx::Rect title_bounds_;
gfx::Rect media_indicator_bounds_;
// The offset used to paint the inactive background image.
@@ -365,9 +360,6 @@ class Tab : public gfx::AnimationDelegate,
// The current color of the close button.
SkColor close_button_color_;
- static gfx::Font* font_;
- static int font_height_;
-
// As the majority of the tabs are inactive, and painting tabs is slowish,
// we cache a handful of the inactive tab backgrounds here.
static ImageCache* image_cache_;
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index 23d564d..15774a9 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -3,12 +3,13 @@
// found in the LICENSE file.
#include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_controller.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/views/tabs/tab_controller.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/models/list_selection_model.h"
#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/label.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
@@ -150,16 +151,18 @@ class TabTest : public views::ViewsTestBase {
const gfx::Rect contents_bounds = tab.GetContentsBounds();
if (tab.ShouldShowIcon()) {
EXPECT_LE(contents_bounds.x(), tab.favicon_bounds_.x());
- if (tab.title_bounds_.width() > 0)
- EXPECT_LE(tab.favicon_bounds_.right(), tab.title_bounds_.x());
+ if (tab.title_->width() > 0)
+ EXPECT_LE(tab.favicon_bounds_.right(), tab.title_->x());
EXPECT_LE(contents_bounds.y(), tab.favicon_bounds_.y());
EXPECT_LE(tab.favicon_bounds_.bottom(), contents_bounds.bottom());
}
if (tab.ShouldShowIcon() && tab.ShouldShowMediaIndicator())
EXPECT_LE(tab.favicon_bounds_.right(), tab.media_indicator_bounds_.x());
if (tab.ShouldShowMediaIndicator()) {
- if (tab.title_bounds_.width() > 0)
- EXPECT_LE(tab.title_bounds_.right(), tab.media_indicator_bounds_.x());
+ if (tab.title_->width() > 0) {
+ EXPECT_LE(tab.title_->bounds().right(),
+ tab.media_indicator_bounds_.x());
+ }
EXPECT_LE(tab.media_indicator_bounds_.right(), contents_bounds.right());
EXPECT_LE(contents_bounds.y(), tab.media_indicator_bounds_.y());
EXPECT_LE(tab.media_indicator_bounds_.bottom(), contents_bounds.bottom());
@@ -174,8 +177,8 @@ class TabTest : public views::ViewsTestBase {
if (tab.ShouldShowCloseBox()) {
// Note: The title bounds can overlap the left-insets of the close box,
// but should otherwise be to the left of the close button.
- if (tab.title_bounds_.width() > 0) {
- EXPECT_LE(tab.title_bounds_.right(),
+ if (tab.title_->width() > 0) {
+ EXPECT_LE(tab.title_->bounds().right(),
tab.close_button_->bounds().x() +
tab.close_button_->GetInsets().left());
}
diff --git a/chrome/browser/ui/views/validation_message_bubble_delegate.cc b/chrome/browser/ui/views/validation_message_bubble_delegate.cc
index 107a873..7c11a10 100644
--- a/chrome/browser/ui/views/validation_message_bubble_delegate.cc
+++ b/chrome/browser/ui/views/validation_message_bubble_delegate.cc
@@ -38,7 +38,7 @@ ValidationMessageBubbleDelegate::ValidationMessageBubbleDelegate(
views::Label* label = new views::Label(
main_text, bundle.GetFontList(ui::ResourceBundle::MediumFont));
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- label->set_directionality_mode(views::Label::AUTO_DETECT_DIRECTIONALITY);
+ label->set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
int text_start_x = kPadding + size.width() + kIconTextMargin;
int min_available = kWindowMinWidth - text_start_x - kPadding;
int max_available = kWindowMaxWidth - text_start_x - kPadding;
@@ -50,8 +50,7 @@ ValidationMessageBubbleDelegate::ValidationMessageBubbleDelegate(
if (!sub_text.empty()) {
sub_label = new views::Label(sub_text);
sub_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- sub_label->set_directionality_mode(
- views::Label::AUTO_DETECT_DIRECTIONALITY);
+ sub_label->set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
label_width = std::max(label_width, sub_label->GetPreferredSize().width());
sub_label->SetMultiLine(true);
AddChildView(sub_label);
diff --git a/ui/gfx/text_constants.h b/ui/gfx/text_constants.h
index e867840..47c91cf 100644
--- a/ui/gfx/text_constants.h
+++ b/ui/gfx/text_constants.h
@@ -20,6 +20,7 @@ enum HorizontalAlignment {
ALIGN_LEFT = 0, // Align the text's left edge with that of its display area.
ALIGN_CENTER, // Align the text's center with that of its display area.
ALIGN_RIGHT, // Align the text's right edge with that of its display area.
+ ALIGN_TO_HEAD, // Align the text to its first strong character's direction.
};
// The directionality modes used to determine the base text direction.
diff --git a/ui/message_center/views/bounded_label.cc b/ui/message_center/views/bounded_label.cc
index 0acad8e..99c66f80 100644
--- a/ui/message_center/views/bounded_label.cc
+++ b/ui/message_center/views/bounded_label.cc
@@ -198,8 +198,11 @@ int InnerBoundedLabel::GetTextFlags() {
if (SkColorGetA(background_color()) != 0xFF)
flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
- if (directionality_mode() ==
- views::Label::AUTO_DETECT_DIRECTIONALITY) {
+ if (directionality_mode() == gfx::DIRECTIONALITY_FORCE_LTR) {
+ flags |= gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
+ } else if (directionality_mode() == gfx::DIRECTIONALITY_FORCE_RTL) {
+ flags |= gfx::Canvas::FORCE_RTL_DIRECTIONALITY;
+ } else if (directionality_mode() == gfx::DIRECTIONALITY_FROM_TEXT) {
base::i18n::TextDirection direction =
base::i18n::GetFirstStrongCharacterDirection(text());
if (direction == base::i18n::RIGHT_TO_LEFT)
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc
index b1fde43..d6647de 100644
--- a/ui/views/controls/button/label_button.cc
+++ b/ui/views/controls/button/label_button.cc
@@ -128,7 +128,7 @@ void LabelButton::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
}
gfx::HorizontalAlignment LabelButton::GetHorizontalAlignment() const {
- return label_->horizontal_alignment();
+ return label_->GetHorizontalAlignment();
}
void LabelButton::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index e9708a3..e1e1bcf 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -120,11 +120,9 @@ void Label::ClearEmbellishing() {
}
void Label::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
- // If the View's UI layout is right-to-left and directionality_mode_ is
- // USE_UI_DIRECTIONALITY, we need to flip the alignment so that the alignment
- // settings take into account the text directionality.
- if (base::i18n::IsRTL() && (directionality_mode_ == USE_UI_DIRECTIONALITY) &&
- (alignment != gfx::ALIGN_CENTER)) {
+ // If the UI layout is right-to-left, flip the alignment direction.
+ if (base::i18n::IsRTL() &&
+ (alignment == gfx::ALIGN_LEFT || alignment == gfx::ALIGN_RIGHT)) {
alignment = (alignment == gfx::ALIGN_LEFT) ?
gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
}
@@ -134,6 +132,15 @@ void Label::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
}
}
+gfx::HorizontalAlignment Label::GetHorizontalAlignment() const {
+ if (horizontal_alignment_ != gfx::ALIGN_TO_HEAD)
+ return horizontal_alignment_;
+
+ const base::i18n::TextDirection dir =
+ base::i18n::GetFirstStrongCharacterDirection(layout_text());
+ return dir == base::i18n::RIGHT_TO_LEFT ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
+}
+
void Label::SetLineHeight(int height) {
if (height != line_height_) {
line_height_ = height;
@@ -405,7 +412,7 @@ void Label::Init(const base::string16& text, const gfx::FontList& font_list) {
allow_character_break_ = false;
elide_behavior_ = gfx::ELIDE_TAIL;
collapse_when_hidden_ = false;
- directionality_mode_ = USE_UI_DIRECTIONALITY;
+ directionality_mode_ = gfx::DIRECTIONALITY_FROM_UI;
enabled_shadow_color_ = 0;
disabled_shadow_color_ = 0;
shadow_offset_.SetPoint(1, 1);
@@ -430,33 +437,27 @@ void Label::RecalculateColors() {
}
gfx::Rect Label::GetTextBounds() const {
- gfx::Rect available_rect(GetAvailableRect());
+ gfx::Rect available(GetAvailableRect());
gfx::Size text_size(GetTextSize());
- text_size.set_width(std::min(available_rect.width(), text_size.width()));
-
- gfx::Insets insets = GetInsets();
- gfx::Point text_origin(insets.left(), insets.top());
- switch (horizontal_alignment_) {
+ text_size.set_width(std::min(available.width(), text_size.width()));
+ gfx::Point origin(GetInsets().left(), GetInsets().top());
+ switch (GetHorizontalAlignment()) {
case gfx::ALIGN_LEFT:
break;
case gfx::ALIGN_CENTER:
- // We put any extra margin pixel on the left rather than the right. We
- // used to do this because measurement on Windows used
- // GetTextExtentPoint32(), which could report a value one too large on the
- // right; we now use DrawText(), and who knows if it can also do this.
- text_origin.Offset((available_rect.width() + 1 - text_size.width()) / 2,
- 0);
+ // Put any extra margin pixel on the left to match the legacy behavior
+ // from the use of GetTextExtentPoint32() on Windows.
+ origin.Offset((available.width() + 1 - text_size.width()) / 2, 0);
break;
case gfx::ALIGN_RIGHT:
- text_origin.set_x(available_rect.right() - text_size.width());
+ origin.set_x(available.right() - text_size.width());
break;
default:
NOTREACHED();
break;
}
- text_origin.Offset(0,
- std::max(0, (available_rect.height() - text_size.height())) / 2);
- return gfx::Rect(text_origin, text_size);
+ origin.Offset(0, std::max(0, (available.height() - text_size.height())) / 2);
+ return gfx::Rect(origin, text_size);
}
int Label::ComputeDrawStringFlags() const {
@@ -466,7 +467,11 @@ int Label::ComputeDrawStringFlags() const {
if (SkColorGetA(background_color_) != 0xFF)
flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
- if (directionality_mode_ == AUTO_DETECT_DIRECTIONALITY) {
+ if (directionality_mode_ == gfx::DIRECTIONALITY_FORCE_LTR) {
+ flags |= gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
+ } else if (directionality_mode_ == gfx::DIRECTIONALITY_FORCE_RTL) {
+ flags |= gfx::Canvas::FORCE_RTL_DIRECTIONALITY;
+ } else if (directionality_mode_ == gfx::DIRECTIONALITY_FROM_TEXT) {
base::i18n::TextDirection direction =
base::i18n::GetFirstStrongCharacterDirection(layout_text());
if (direction == base::i18n::RIGHT_TO_LEFT)
@@ -475,7 +480,7 @@ int Label::ComputeDrawStringFlags() const {
flags |= gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
}
- switch (horizontal_alignment_) {
+ switch (GetHorizontalAlignment()) {
case gfx::ALIGN_LEFT:
flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
break;
@@ -485,6 +490,9 @@ int Label::ComputeDrawStringFlags() const {
case gfx::ALIGN_RIGHT:
flags |= gfx::Canvas::TEXT_ALIGN_RIGHT;
break;
+ default:
+ NOTREACHED();
+ break;
}
if (!is_multi_line_)
diff --git a/ui/views/controls/label.h b/ui/views/controls/label.h
index 9e2881d..60dfba9 100644
--- a/ui/views/controls/label.h
+++ b/ui/views/controls/label.h
@@ -18,30 +18,9 @@
namespace views {
-/////////////////////////////////////////////////////////////////////////////
-//
-// Label class
-//
-// A label is a view subclass that can display a string.
-//
-/////////////////////////////////////////////////////////////////////////////
+// A view subclass that can display a string.
class VIEWS_EXPORT Label : public View {
public:
- // The following enum is used to indicate whether using the Chrome UI's
- // directionality as the label's directionality, or auto-detecting the label's
- // directionality.
- //
- // If the label text originates from the Chrome UI, we should use the Chrome
- // UI's directionality as the label's directionality.
- //
- // If the text originates from a web page, its directionality is determined
- // based on its first character with strong directionality, disregarding what
- // directionality the Chrome UI is.
- enum DirectionalityMode {
- USE_UI_DIRECTIONALITY = 0,
- AUTO_DETECT_DIRECTIONALITY
- };
-
// Internal class name.
static const char kViewClassName[];
@@ -94,28 +73,17 @@ class VIEWS_EXPORT Label : public View {
// Set the color of a halo on the painted text (use transparent for none).
void set_halo_color(SkColor halo_color) { halo_color_ = halo_color; }
- // Sets horizontal alignment. If the locale is RTL, and the directionality
- // mode is USE_UI_DIRECTIONALITY, the alignment is flipped around.
- //
- // Caveat: for labels originating from a web page, the directionality mode
- // should be reset to AUTO_DETECT_DIRECTIONALITY before the horizontal
- // alignment is set. Otherwise, the label's alignment specified as a parameter
- // will be flipped in RTL locales.
+ // Sets the horizontal alignment; the argument value is mirrored in RTL UI.
void SetHorizontalAlignment(gfx::HorizontalAlignment alignment);
+ gfx::HorizontalAlignment GetHorizontalAlignment() const;
- gfx::HorizontalAlignment horizontal_alignment() const {
- return horizontal_alignment_;
- }
-
- // Sets the directionality mode. The directionality mode is initialized to
- // USE_UI_DIRECTIONALITY when the label is constructed. USE_UI_DIRECTIONALITY
- // applies to every label that originates from the Chrome UI. However, if the
- // label originates from a web page, its directionality is auto-detected.
- void set_directionality_mode(DirectionalityMode mode) {
+ // Sets the directionality mode. The default value is DIRECTIONALITY_FROM_UI,
+ // which should be suitable for most text originating from UI string assets.
+ // Most text originating from web content should use DIRECTIONALITY_FROM_TEXT.
+ void set_directionality_mode(gfx::DirectionalityMode mode) {
directionality_mode_ = mode;
}
-
- DirectionalityMode directionality_mode() const {
+ gfx::DirectionalityMode directionality_mode() const {
return directionality_mode_;
}
@@ -212,9 +180,7 @@ class VIEWS_EXPORT Label : public View {
FRIEND_TEST_ALL_PREFIXES(LabelTest, DrawMultiLineString);
FRIEND_TEST_ALL_PREFIXES(LabelTest, DrawSingleLineStringInRTL);
FRIEND_TEST_ALL_PREFIXES(LabelTest, DrawMultiLineStringInRTL);
- FRIEND_TEST_ALL_PREFIXES(LabelTest, AutoDetectDirectionality);
-
- // Calls ComputeDrawStringFlags().
+ FRIEND_TEST_ALL_PREFIXES(LabelTest, DirectionalityFromText);
FRIEND_TEST_ALL_PREFIXES(LabelTest, DisableSubpixelRendering);
// Sets both |text_| and |layout_text_| to appropriate values, taking
@@ -272,10 +238,9 @@ class VIEWS_EXPORT Label : public View {
base::string16 tooltip_text_;
// Whether to collapse the label when it's not visible.
bool collapse_when_hidden_;
- // The following member variable is used to control whether the
- // directionality is auto-detected based on first strong directionality
- // character or is determined by chrome UI's locale.
- DirectionalityMode directionality_mode_;
+ // Controls whether the directionality is auto-detected based on first strong
+ // directionality character or is determined by the application UI's locale.
+ gfx::DirectionalityMode directionality_mode_;
// Colors for shadow.
SkColor enabled_shadow_color_;
diff --git a/ui/views/controls/label_unittest.cc b/ui/views/controls/label_unittest.cc
index 5825b6c..1ff16b4 100644
--- a/ui/views/controls/label_unittest.cc
+++ b/ui/views/controls/label_unittest.cc
@@ -19,6 +19,13 @@ namespace views {
// All text sizing measurements (width and height) should be greater than this.
const int kMinTextDimension = 4;
+// A test utility function to set the application default text direction.
+void SetRTL(bool rtl) {
+ // Override the current locale/direction.
+ base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
+ EXPECT_EQ(rtl, base::i18n::IsRTL());
+}
+
TEST(LabelTest, FontPropertySymbol) {
Label label;
std::string font_name("symbol");
@@ -55,38 +62,45 @@ TEST(LabelTest, ColorProperty) {
}
TEST(LabelTest, AlignmentProperty) {
- Label label;
- bool reverse_alignment = base::i18n::IsRTL();
-
- label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
- EXPECT_EQ(reverse_alignment ? gfx::ALIGN_LEFT : gfx::ALIGN_RIGHT,
- label.horizontal_alignment());
- label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
- EXPECT_EQ(reverse_alignment ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT,
- label.horizontal_alignment());
- label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
- EXPECT_EQ(gfx::ALIGN_CENTER, label.horizontal_alignment());
+ const bool was_rtl = base::i18n::IsRTL();
- // The label's alignment should not be flipped if the directionality mode is
- // AUTO_DETECT_DIRECTIONALITY.
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
- label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
- EXPECT_EQ(gfx::ALIGN_RIGHT, label.horizontal_alignment());
- label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
- EXPECT_EQ(gfx::ALIGN_LEFT, label.horizontal_alignment());
- label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
- EXPECT_EQ(gfx::ALIGN_CENTER, label.horizontal_alignment());
+ Label label;
+ for (size_t i = 0; i < 2; ++i) {
+ // Toggle the application default text direction (to try each direction).
+ SetRTL(!base::i18n::IsRTL());
+ bool reverse_alignment = base::i18n::IsRTL();
+
+ // The alignment should be flipped in RTL UI.
+ label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
+ EXPECT_EQ(reverse_alignment ? gfx::ALIGN_LEFT : gfx::ALIGN_RIGHT,
+ label.GetHorizontalAlignment());
+ label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ EXPECT_EQ(reverse_alignment ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT,
+ label.GetHorizontalAlignment());
+ label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
+ EXPECT_EQ(gfx::ALIGN_CENTER, label.GetHorizontalAlignment());
+
+ for (size_t j = 0; j < 2; ++j) {
+ label.SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
+ const bool rtl = j == 0;
+ label.SetText(rtl ? base::WideToUTF16(L"\x5d0") : ASCIIToUTF16("A"));
+ EXPECT_EQ(rtl ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT,
+ label.GetHorizontalAlignment());
+ }
+ }
+
+ EXPECT_EQ(was_rtl, base::i18n::IsRTL());
}
TEST(LabelTest, DirectionalityModeProperty) {
Label label;
- EXPECT_EQ(Label::USE_UI_DIRECTIONALITY, label.directionality_mode());
+ EXPECT_EQ(gfx::DIRECTIONALITY_FROM_UI, label.directionality_mode());
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
- EXPECT_EQ(Label::AUTO_DETECT_DIRECTIONALITY, label.directionality_mode());
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
+ EXPECT_EQ(gfx::DIRECTIONALITY_FROM_TEXT, label.directionality_mode());
- label.set_directionality_mode(Label::USE_UI_DIRECTIONALITY);
- EXPECT_EQ(Label::USE_UI_DIRECTIONALITY, label.directionality_mode());
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FROM_UI);
+ EXPECT_EQ(gfx::DIRECTIONALITY_FROM_UI, label.directionality_mode());
}
TEST(LabelTest, MultiLineProperty) {
@@ -317,20 +331,16 @@ TEST(LabelTest, MultiLineSizing) {
required_size.width() + border.width());
}
-TEST(LabelTest, AutoDetectDirectionality) {
+TEST(LabelTest, DirectionalityFromText) {
Label label;
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
+ label.SetBounds(0, 0, 1000, 1000);
+ base::string16 paint_text;
+ gfx::Rect text_bounds;
+ int flags = -1;
// Test text starts with RTL character.
label.SetText(base::WideToUTF16(L" \x5d0\x5d1\x5d2 abc"));
- gfx::Size required_size(label.GetPreferredSize());
- gfx::Size extra(22, 8);
- label.SetBounds(0, 0, required_size.width() + extra.width(),
- required_size.height() + extra.height());
-
- base::string16 paint_text;
- gfx::Rect text_bounds;
- int flags;
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
EXPECT_EQ(gfx::Canvas::FORCE_RTL_DIRECTIONALITY,
flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY |
@@ -338,10 +348,6 @@ TEST(LabelTest, AutoDetectDirectionality) {
// Test text starts with LTR character.
label.SetText(base::WideToUTF16(L"ltr \x5d0\x5d1\x5d2 abc"));
- required_size = label.GetPreferredSize();
- label.SetBounds(0, 0, required_size.width() + extra.width(),
- required_size.height() + extra.height());
-
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
EXPECT_EQ(gfx::Canvas::FORCE_LTR_DIRECTIONALITY,
flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY |
@@ -351,10 +357,8 @@ TEST(LabelTest, AutoDetectDirectionality) {
TEST(LabelTest, DrawSingleLineString) {
Label label;
label.SetFocusable(false);
-
- // Turn off mirroring so that we don't need to figure out if
- // align right really means align left.
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
+ // Force a directionality to simplify alignment value testing.
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FORCE_LTR);
label.SetText(ASCIIToUTF16("Here's a string with no returns."));
gfx::Size required_size(label.GetPreferredSize());
@@ -365,7 +369,7 @@ TEST(LabelTest, DrawSingleLineString) {
// Do some basic verifications for all three alignments.
base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
// Centered text.
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
@@ -474,16 +478,14 @@ TEST(LabelTest, DrawSingleLineString) {
gfx::Canvas::TEXT_ALIGN_RIGHT));
}
-// On Linux the underlying pango routines require a max height in order to
-// ellide multiline text. So until that can be resolved, we set all
-// multiline lables to not ellide in Linux only.
+// Pango needs a max height to elide multiline text; that is not supported here.
TEST(LabelTest, DrawMultiLineString) {
Label label;
label.SetFocusable(false);
-
- // Turn off mirroring so that we don't need to figure out if
- // align right really means align left.
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
+ // Force a directionality to simplify alignment value testing.
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FORCE_LTR);
+ // Set a background color to prevent gfx::Canvas::NO_SUBPIXEL_RENDERING flags.
+ label.SetBackgroundColor(SK_ColorWHITE);
label.SetText(ASCIIToUTF16("Another string\nwith returns\n\n!"));
label.SetMultiLine(true);
@@ -496,7 +498,7 @@ TEST(LabelTest, DrawMultiLineString) {
// Do some basic verifications for all three alignments.
base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width() / 2, text_bounds.x());
@@ -509,7 +511,7 @@ TEST(LabelTest, DrawMultiLineString) {
#if !defined(OS_WIN)
expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
- EXPECT_EQ(expected_flags, expected_flags & flags);
+ EXPECT_EQ(expected_flags, expected_flags);
gfx::Rect center_bounds(text_bounds);
label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -527,7 +529,7 @@ TEST(LabelTest, DrawMultiLineString) {
#if !defined(OS_WIN)
expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
- EXPECT_EQ(expected_flags, expected_flags & flags);
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
@@ -544,7 +546,7 @@ TEST(LabelTest, DrawMultiLineString) {
#if !defined(OS_WIN)
expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
- EXPECT_EQ(expected_flags, expected_flags & flags);
+ EXPECT_EQ(expected_flags, expected_flags);
// Test multiline drawing with a border.
gfx::Insets border(19, 92, 23, 2);
@@ -570,7 +572,7 @@ TEST(LabelTest, DrawMultiLineString) {
#if !defined(OS_WIN)
expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
- EXPECT_EQ(expected_flags, expected_flags & flags);
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
paint_text.clear();
@@ -587,7 +589,7 @@ TEST(LabelTest, DrawMultiLineString) {
#if !defined(OS_WIN)
expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
- EXPECT_EQ(expected_flags, expected_flags & flags);
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
@@ -604,7 +606,7 @@ TEST(LabelTest, DrawMultiLineString) {
#if !defined(OS_WIN)
expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
- EXPECT_EQ(expected_flags, expected_flags & flags);
+ EXPECT_EQ(expected_flags, expected_flags);
}
TEST(LabelTest, DrawSingleLineStringInRTL) {
@@ -623,7 +625,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
// Do some basic verifications for all three alignments.
base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
// Centered text.
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
@@ -758,7 +760,7 @@ TEST(LabelTest, DrawMultiLineStringInRTL) {
// Do some basic verifications for all three alignments.
base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width() / 2, text_bounds.x());
diff --git a/ui/views/controls/message_box_view.cc b/ui/views/controls/message_box_view.cc
index 20caaa8..671ca61 100644
--- a/ui/views/controls/message_box_view.cc
+++ b/ui/views/controls/message_box_view.cc
@@ -177,21 +177,13 @@ void MessageBoxView::Init(const InitParams& params) {
if (params.options & DETECT_DIRECTIONALITY) {
std::vector<base::string16> texts;
SplitStringIntoParagraphs(params.message, &texts);
- // If the text originates from a web page, its alignment is based on its
- // first character with strong directionality.
- base::i18n::TextDirection message_direction =
- base::i18n::GetFirstStrongCharacterDirection(params.message);
- gfx::HorizontalAlignment alignment =
- (message_direction == base::i18n::RIGHT_TO_LEFT) ?
- gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
for (size_t i = 0; i < texts.size(); ++i) {
Label* message_label = new Label(texts[i]);
- // Don't set multi-line to true if the text is empty, else the label will
- // have a height of 0.
+ // Avoid empty multi-line labels, which have a height of 0.
message_label->SetMultiLine(!texts[i].empty());
message_label->SetAllowCharacterBreak(true);
- message_label->set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
- message_label->SetHorizontalAlignment(alignment);
+ message_label->set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
+ message_label->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
message_labels_.push_back(message_label);
}
} else {