diff options
author | msw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-12 07:41:47 +0000 |
---|---|---|
committer | msw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-12 07:41:47 +0000 |
commit | 5f751daa2ab57bee299526a9a25b2d692513bdd1 (patch) | |
tree | 13bbc9a853a7835d2c8fea1f74837b564ba98f8b | |
parent | 19c602f19f20eab4ad2a5ac015eb70b254ccedb0 (diff) | |
download | chromium_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.cc | 102 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab.h | 14 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_unittest.cc | 17 | ||||
-rw-r--r-- | chrome/browser/ui/views/validation_message_bubble_delegate.cc | 5 | ||||
-rw-r--r-- | ui/gfx/text_constants.h | 1 | ||||
-rw-r--r-- | ui/message_center/views/bounded_label.cc | 7 | ||||
-rw-r--r-- | ui/views/controls/button/label_button.cc | 2 | ||||
-rw-r--r-- | ui/views/controls/label.cc | 56 | ||||
-rw-r--r-- | ui/views/controls/label.h | 59 | ||||
-rw-r--r-- | ui/views/controls/label_unittest.cc | 122 | ||||
-rw-r--r-- | ui/views/controls/message_box_view.cc | 14 |
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 { |