summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/jsmessage_box_handler_win.cc5
-rw-r--r--chrome/common/gfx/chrome_canvas_win.cc44
-rw-r--r--chrome/common/l10n_util.cc34
-rw-r--r--chrome/common/l10n_util.h8
-rw-r--r--chrome/common/l10n_util_unittest.cc96
-rw-r--r--chrome/views/label.cc28
-rw-r--r--chrome/views/label.h41
-rw-r--r--chrome/views/label_unittest.cc21
-rw-r--r--chrome/views/message_box_view.cc19
-rw-r--r--chrome/views/message_box_view.h16
10 files changed, 289 insertions, 23 deletions
diff --git a/chrome/browser/jsmessage_box_handler_win.cc b/chrome/browser/jsmessage_box_handler_win.cc
index 979e7e6..5026e8e 100644
--- a/chrome/browser/jsmessage_box_handler_win.cc
+++ b/chrome/browser/jsmessage_box_handler_win.cc
@@ -43,8 +43,9 @@ JavascriptMessageBoxHandler::JavascriptMessageBoxHandler(
reply_msg_(reply_msg),
dialog_flags_(dialog_flags),
dialog_(NULL),
- message_box_view_(new MessageBoxView(dialog_flags, message_text,
- default_prompt_text)) {
+ message_box_view_(new MessageBoxView(
+ dialog_flags | MessageBoxView::kAutoDetectAlignment,
+ message_text, default_prompt_text)) {
DCHECK(message_box_view_);
DCHECK(reply_msg_);
diff --git a/chrome/common/gfx/chrome_canvas_win.cc b/chrome/common/gfx/chrome_canvas_win.cc
index f28b0cb..770effb 100644
--- a/chrome/common/gfx/chrome_canvas_win.cc
+++ b/chrome/common/gfx/chrome_canvas_win.cc
@@ -21,9 +21,14 @@ void DoDrawText(HDC hdc, const std::wstring& text,
std::wstring localized_text;
const wchar_t* string_ptr = text.c_str();
int string_size = static_cast<int>(text.length());
- if (l10n_util::AdjustStringForLocaleDirection(text, &localized_text)) {
- string_ptr = localized_text.c_str();
- string_size = static_cast<int>(localized_text.length());
+ // Only adjust string directionality if both of the following are true:
+ // 1. The current locale is RTL.
+ // 2. The string itself has RTL directionality.
+ if (flags & DT_RTLREADING) {
+ if (l10n_util::AdjustStringForLocaleDirection(text, &localized_text)) {
+ string_ptr = localized_text.c_str();
+ string_size = static_cast<int>(localized_text.length());
+ }
}
DrawText(hdc, string_ptr, string_size, text_bounds, flags);
@@ -31,7 +36,7 @@ void DoDrawText(HDC hdc, const std::wstring& text,
// Compute the windows flags necessary to implement the provided text
// ChromeCanvas flags.
-int ComputeFormatFlags(int flags) {
+int ComputeFormatFlags(int flags, const std::wstring& text) {
int f = 0;
// Setting the text alignment explicitly in case it hasn't already been set.
@@ -82,9 +87,30 @@ int ComputeFormatFlags(int flags) {
// English) this flag also makes sure that if there is not enough space to
// display the entire string, the ellipsis is displayed on the left hand side
// of the truncated string and not on the right hand side.
- if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
- f |= DT_RTLREADING;
-
+ //
+ // We make a distinction between Chrome UI strings and text coming from a web
+ // page.
+ //
+ // For text coming from a web page we determine the alignment based on the
+ // first character with strong directionality. If the directionality of the
+ // first character with strong directionality in the text is LTR, the
+ // alignment is set to DT_LEFT, and the directionality should not be set as
+ // DT_RTLREADING.
+ //
+ // This heuristic doesn't work for Chrome UI strings since even in RTL
+ // locales, some of those might start with English text but we know they're
+ // localized so we always want them to be right aligned, and their
+ // directionality should be set as DT_RTLREADING.
+ //
+ // Caveat: If the string is purely LTR, don't set DTL_RTLREADING since when
+ // the flag is set, LRE-PDF don't have the desired effect of rendering
+ // multiline English-only text as LTR.
+ if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT &&
+ (f & DT_RIGHT)) {
+ if (l10n_util::StringContainsStrongRTLChars(text)) {
+ f |= DT_RTLREADING;
+ }
+ }
return f;
}
@@ -115,7 +141,7 @@ void ChromeCanvas::SizeStringInt(const std::wstring& text,
b.right = 1;
}
b.bottom = *height;
- DoDrawText(dc, text, &b, ComputeFormatFlags(flags) | DT_CALCRECT);
+ DoDrawText(dc, text, &b, ComputeFormatFlags(flags, text) | DT_CALCRECT);
// Restore the old font. This way we don't have to worry if the caller
// deletes the font and the DC lives longer.
@@ -141,7 +167,7 @@ void ChromeCanvas::DrawStringInt(const std::wstring& text, HFONT font,
SkColorGetB(color));
SetTextColor(dc, brush_color);
- int f = ComputeFormatFlags(flags);
+ int f = ComputeFormatFlags(flags, text);
DoDrawText(dc, text, &text_bounds, f);
endPlatformPaint();
diff --git a/chrome/common/l10n_util.cc b/chrome/common/l10n_util.cc
index 6365291..6fb5286 100644
--- a/chrome/common/l10n_util.cc
+++ b/chrome/common/l10n_util.cc
@@ -502,6 +502,40 @@ TextDirection GetTextDirection() {
return g_text_direction;
}
+TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) {
+#if defined(WCHAR_T_IS_UTF32)
+ string16 text_utf16 = WideToUTF16(text);
+ const UChar* string = text_utf16.c_str();
+#else
+ const UChar* string = text.c_str();
+#endif
+ size_t length = text.length();
+ size_t position = 0;
+ while (position < length) {
+ UChar32 character;
+ size_t next_position = position;
+ U16_NEXT(string, next_position, length, character);
+
+ // Now that we have the character, we use ICU in order to query for the
+ // appropriate Unicode BiDi character type.
+ int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+ if ((property == U_RIGHT_TO_LEFT) ||
+ (property == U_RIGHT_TO_LEFT_ARABIC) ||
+ (property == U_RIGHT_TO_LEFT_EMBEDDING) ||
+ (property == U_RIGHT_TO_LEFT_OVERRIDE)) {
+ return RIGHT_TO_LEFT;
+ } else if ((property == U_LEFT_TO_RIGHT) ||
+ (property == U_LEFT_TO_RIGHT_EMBEDDING) ||
+ (property == U_LEFT_TO_RIGHT_OVERRIDE)) {
+ return LEFT_TO_RIGHT;
+ }
+
+ position = next_position;
+ }
+
+ return LEFT_TO_RIGHT;
+}
+
bool AdjustStringForLocaleDirection(const std::wstring& text,
std::wstring* localized_text) {
if (GetTextDirection() == LEFT_TO_RIGHT || text.length() == 0)
diff --git a/chrome/common/l10n_util.h b/chrome/common/l10n_util.h
index 0c67712..c0a5d0d 100644
--- a/chrome/common/l10n_util.h
+++ b/chrome/common/l10n_util.h
@@ -116,6 +116,14 @@ enum TextDirection {
// * UNKNOWN_DIRECTION: unknown (or error).
TextDirection GetTextDirection();
+// Given the string in |text|, returns the directionality of the first
+// character with strong directionality in the string. If no character in the
+// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi
+// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong
+// directionality characters. Please refer to http://unicode.org/reports/tr9/
+// for more information.
+TextDirection GetFirstStrongCharacterDirection(const std::wstring& text);
+
// Given the string in |text|, this function creates a copy of the string with
// the appropriate Unicode formatting marks that mark the string direction
// (either left-to-right or right-to-left). The new string is returned in
diff --git a/chrome/common/l10n_util_unittest.cc b/chrome/common/l10n_util_unittest.cc
index 3d93ef7..88c1cad 100644
--- a/chrome/common/l10n_util_unittest.cc
+++ b/chrome/common/l10n_util_unittest.cc
@@ -160,6 +160,102 @@ TEST_F(L10nUtilTest, GetAppLocale) {
Locale::setDefault(locale, error_code);
}
+TEST_F(L10nUtilTest, GetFirstStrongCharacterDirection) {
+ // Test pure LTR string.
+ std::wstring string(L"foo bar");
+ EXPECT_EQ(l10n_util::LEFT_TO_RIGHT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type L.
+ string.assign(L"foo \x05d0 bar");
+ EXPECT_EQ(l10n_util::LEFT_TO_RIGHT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type R.
+ string.assign(L"\x05d0 foo bar");
+ EXPECT_EQ(l10n_util::RIGHT_TO_LEFT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string which starts with a character with weak directionality
+ // and in which the first character with strong directionality is a character
+ // with type L.
+ string.assign(L"!foo \x05d0 bar");
+ EXPECT_EQ(l10n_util::LEFT_TO_RIGHT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string which starts with a character with weak directionality
+ // and in which the first character with strong directionality is a character
+ // with type R.
+ string.assign(L",\x05d0 foo bar");
+ EXPECT_EQ(l10n_util::RIGHT_TO_LEFT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type LRE.
+ string.assign(L"\x202a \x05d0 foo bar");
+ EXPECT_EQ(l10n_util::LEFT_TO_RIGHT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type LRO.
+ string.assign(L"\x202d \x05d0 foo bar");
+ EXPECT_EQ(l10n_util::LEFT_TO_RIGHT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type RLE.
+ string.assign(L"\x202b foo \x05d0 bar");
+ EXPECT_EQ(l10n_util::RIGHT_TO_LEFT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type RLO.
+ string.assign(L"\x202e foo \x05d0 bar");
+ EXPECT_EQ(l10n_util::RIGHT_TO_LEFT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type AL.
+ string.assign(L"\x0622 foo \x05d0 bar");
+ EXPECT_EQ(l10n_util::RIGHT_TO_LEFT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test a string without strong directionality characters.
+ string.assign(L",!.{}");
+ EXPECT_EQ(l10n_util::LEFT_TO_RIGHT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test empty string.
+ string.assign(L"");
+ EXPECT_EQ(l10n_util::LEFT_TO_RIGHT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+ // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
+ // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
+ // information).
+#if defined(WCHAR_T_IS_UTF32)
+ string.assign(L" ! \x10910" L"abc 123");
+#elif defined(WCHAR_T_IS_UTF16)
+ string.assign(L" ! \xd802\xdd10" L"abc 123");
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+ EXPECT_EQ(l10n_util::RIGHT_TO_LEFT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+
+#if defined(WCHAR_T_IS_UTF32)
+ string.assign(L" ! \x10401" L"abc 123");
+#elif defined(WCHAR_T_IS_UTF16)
+ string.assign(L" ! \xd801\xdc01" L"abc 123");
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+ EXPECT_EQ(l10n_util::LEFT_TO_RIGHT,
+ l10n_util::GetFirstStrongCharacterDirection(string));
+}
+
typedef struct {
std::wstring path;
std::wstring wrapped_path;
diff --git a/chrome/views/label.cc b/chrome/views/label.cc
index f0c38d8..0489479 100644
--- a/chrome/views/label.cc
+++ b/chrome/views/label.cc
@@ -45,6 +45,7 @@ void Label::Init(const std::wstring& text, const ChromeFont& font) {
horiz_alignment_ = ALIGN_CENTER;
is_multi_line_ = false;
collapse_when_hidden_ = false;
+ rtl_alignment_mode_ = USE_UI_ALIGNMENT;
}
Label::~Label() {
@@ -238,17 +239,16 @@ const SkColor Label::GetColor() const {
}
void Label::SetHorizontalAlignment(Alignment a) {
+ // If the View's UI layout is right-to-left and rtl_alignment_mode_ is
+ // USE_UI_ALIGNMENT, we need to flip the alignment so that the alignment
+ // settings take into account the text directionality.
+ if (UILayoutIsRightToLeft() && rtl_alignment_mode_ == USE_UI_ALIGNMENT) {
+ if (a == ALIGN_LEFT)
+ a = ALIGN_RIGHT;
+ else if (a == ALIGN_RIGHT)
+ a = ALIGN_LEFT;
+ }
if (horiz_alignment_ != a) {
-
- // If the View's UI layout is right-to-left, we need to flip the alignment
- // so that the alignment settings take into account the text
- // directionality.
- if (UILayoutIsRightToLeft()) {
- if (a == ALIGN_LEFT)
- a = ALIGN_RIGHT;
- else if (a == ALIGN_RIGHT)
- a = ALIGN_LEFT;
- }
horiz_alignment_ = a;
SchedulePaint();
}
@@ -258,6 +258,14 @@ Label::Alignment Label::GetHorizontalAlignment() const {
return horiz_alignment_;
}
+void Label::SetRTLAlignmentMode(RTLAlignmentMode mode) {
+ rtl_alignment_mode_ = mode;
+}
+
+Label::RTLAlignmentMode Label::GetRTLAlignmentMode() const {
+ return rtl_alignment_mode_;
+}
+
void Label::SetMultiLine(bool f) {
if (f != is_multi_line_) {
is_multi_line_ = f;
diff --git a/chrome/views/label.h b/chrome/views/label.h
index 84e685c..d70ff3a 100644
--- a/chrome/views/label.h
+++ b/chrome/views/label.h
@@ -26,6 +26,22 @@ class Label : public View {
ALIGN_CENTER,
ALIGN_RIGHT };
+ // The following enum is used to indicate whether using the Chrome UI's
+ // alignment as the label's alignment, or autodetecting the label's
+ // alignment.
+ //
+ // If the label text originates from the Chrome UI, we should use the Chrome
+ // UI's alignment as the label's alignment.
+ //
+ // If the text originates from a web page, the text's alignment is determined
+ // based on the first character with strong directionality, disregarding what
+ // directionality the Chrome UI is. And its alignment will not be flipped
+ // around in RTL locales.
+ enum RTLAlignmentMode {
+ USE_UI_ALIGNMENT = 0,
+ AUTO_DETECT_ALIGNMENT
+ };
+
// The view class name.
static const char kViewClassName[];
@@ -81,10 +97,29 @@ class Label : public View {
// Return a reference to the currently used color
virtual const SkColor GetColor() const;
- // Alignment
+ // Set horizontal alignment. If the locale is RTL, and the RTL alignment
+ // setting is set as USE_UI_ALIGNMENT, the alignment is flipped around.
+ //
+ // Caveat: for labels originating from a web page, the RTL alignment mode
+ // should be reset to AUTO_DETECT_ALIGNMENT before the horizontal alignment
+ // is set. Otherwise, the label's alignment specified as a parameter will be
+ // flipped in RTL locales. Please see the comments in SetRTLAlignmentMode for
+ // more information.
void SetHorizontalAlignment(Alignment a);
+
Alignment GetHorizontalAlignment() const;
+ // Set the RTL alignment mode. The RTL alignment mode is initialized to
+ // USE_UI_ALIGNMENT when the label is constructed. USE_UI_ALIGNMENT applies
+ // to every label that originates from the Chrome UI. However, if the label
+ // originates from a web page, its alignment should not be flipped around for
+ // RTL locales. For such labels, we need to set the RTL alignment mode to
+ // AUTO_DETECT_ALIGNMENT so that subsequent SetHorizontalAlignment() calls
+ // will not flip the label's alignment around.
+ void SetRTLAlignmentMode(RTLAlignmentMode mode);
+
+ RTLAlignmentMode GetRTLAlignmentMode() const;
+
// Set whether the label text can wrap on multiple lines.
// Default is false
void SetMultiLine(bool f);
@@ -192,6 +227,10 @@ class Label : public View {
scoped_ptr<Background> mouse_over_background_;
// Whether to collapse the label when it's not visible.
bool collapse_when_hidden_;
+ // The following member variable is used to control whether the alignment
+ // needs to be flipped around for RTL locales. Please refer to the definition
+ // of RTLAlignmentMode for more information.
+ RTLAlignmentMode rtl_alignment_mode_;
DISALLOW_COPY_AND_ASSIGN(Label);
};
diff --git a/chrome/views/label_unittest.cc b/chrome/views/label_unittest.cc
index e1f80bb0..96b4d63 100644
--- a/chrome/views/label_unittest.cc
+++ b/chrome/views/label_unittest.cc
@@ -61,6 +61,27 @@ TEST(LabelTest, AlignmentProperty) {
label.GetHorizontalAlignment());
label.SetHorizontalAlignment(Label::ALIGN_CENTER);
EXPECT_EQ(Label::ALIGN_CENTER, label.GetHorizontalAlignment());
+
+ // The label's alignment should not be flipped if the RTL alignment mode
+ // is AUTO_DETECT_ALIGNMENT.
+ label.SetRTLAlignmentMode(Label::AUTO_DETECT_ALIGNMENT);
+ label.SetHorizontalAlignment(Label::ALIGN_RIGHT);
+ EXPECT_EQ(Label::ALIGN_RIGHT, label.GetHorizontalAlignment());
+ label.SetHorizontalAlignment(Label::ALIGN_LEFT);
+ EXPECT_EQ(Label::ALIGN_LEFT, label.GetHorizontalAlignment());
+ label.SetHorizontalAlignment(Label::ALIGN_CENTER);
+ EXPECT_EQ(Label::ALIGN_CENTER, label.GetHorizontalAlignment());
+}
+
+TEST(LabelTest, RTLAlignmentModeProperty) {
+ Label label;
+ EXPECT_EQ(Label::USE_UI_ALIGNMENT, label.GetRTLAlignmentMode());
+
+ label.SetRTLAlignmentMode(Label::AUTO_DETECT_ALIGNMENT);
+ EXPECT_EQ(Label::AUTO_DETECT_ALIGNMENT, label.GetRTLAlignmentMode());
+
+ label.SetRTLAlignmentMode(Label::USE_UI_ALIGNMENT);
+ EXPECT_EQ(Label::USE_UI_ALIGNMENT, label.GetRTLAlignmentMode());
}
TEST(LabelTest, MultiLineProperty) {
diff --git a/chrome/views/message_box_view.cc b/chrome/views/message_box_view.cc
index 818cf50..26fd1c2 100644
--- a/chrome/views/message_box_view.cc
+++ b/chrome/views/message_box_view.cc
@@ -94,7 +94,24 @@ void MessageBoxView::ViewHierarchyChanged(bool is_add,
void MessageBoxView::Init(int dialog_flags,
const std::wstring& default_prompt) {
message_label_->SetMultiLine(true);
- message_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ if (dialog_flags & kAutoDetectAlignment) {
+ // Determine the alignment and directionality based on the first character
+ // with strong directionality.
+ l10n_util::TextDirection direction =
+ l10n_util::GetFirstStrongCharacterDirection(message_label_->GetText());
+ views::Label::Alignment alignment;
+ if (direction == l10n_util::RIGHT_TO_LEFT)
+ alignment = views::Label::ALIGN_RIGHT;
+ else
+ alignment = views::Label::ALIGN_LEFT;
+ // In addition, we should set the RTL alignment mode as
+ // AUTO_DETECT_ALIGNMENT so that the alignment will not be flipped around
+ // in RTL locales.
+ message_label_->SetRTLAlignmentMode(views::Label::AUTO_DETECT_ALIGNMENT);
+ message_label_->SetHorizontalAlignment(alignment);
+ } else {
+ message_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ }
if (dialog_flags & kFlagHasPromptField) {
prompt_field_ = new views::TextField;
diff --git a/chrome/views/message_box_view.h b/chrome/views/message_box_view.h
index a8f0dca..e71db2c 100644
--- a/chrome/views/message_box_view.h
+++ b/chrome/views/message_box_view.h
@@ -25,6 +25,22 @@ class MessageBoxView : public views::View {
static const int kFlagHasPromptField = 0x4;
static const int kFlagHasMessage = 0x8;
+ // The following flag is used to indicate whether the message's alignment
+ // should be autodetected or inherited from Chrome UI. Callers should pass
+ // the correct flag based on the origin of the message. If the message is
+ // from a web page (such as the JavaScript alert message), its alignment and
+ // directionality are based on the first character with strong directionality
+ // in the message. Chrome UI strings are localized string and therefore they
+ // should have the same alignment and directionality as those of the Chrome
+ // UI. For example, in RTL locales, even though some strings might begin with
+ // an English character, they should still be right aligned and be displayed
+ // Right-To-Left.
+ //
+ // TODO(xji): If the message is from a web page, then the message
+ // directionality should be determined based on the directionality of the web
+ // page. Please refer to http://crbug.com/7166 for more information.
+ static const int kAutoDetectAlignment = 0x10;
+
static const int kIsConfirmMessageBox = kFlagHasMessage |
kFlagHasOKButton |
kFlagHasCancelButton;