summaryrefslogtreecommitdiffstats
path: root/chromium/ui/views/controls
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/ui/views/controls
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/ui/views/controls')
-rw-r--r--chromium/ui/views/controls/button/blue_button.cc83
-rw-r--r--chromium/ui/views/controls/button/blue_button.h1
-rw-r--r--chromium/ui/views/controls/button/blue_button_unittest.cc59
-rw-r--r--chromium/ui/views/controls/button/button.cc28
-rw-r--r--chromium/ui/views/controls/button/button.h16
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc14
-rw-r--r--chromium/ui/views/controls/button/checkbox.h4
-rw-r--r--chromium/ui/views/controls/button/custom_button.cc15
-rw-r--r--chromium/ui/views/controls/button/custom_button.h6
-rw-r--r--chromium/ui/views/controls/button/custom_button_unittest.cc24
-rw-r--r--chromium/ui/views/controls/button/image_button.cc23
-rw-r--r--chromium/ui/views/controls/button/image_button.h17
-rw-r--r--chromium/ui/views/controls/button/image_button_unittest.cc25
-rw-r--r--chromium/ui/views/controls/button/label_button.cc161
-rw-r--r--chromium/ui/views/controls/button/label_button.h54
-rw-r--r--chromium/ui/views/controls/button/label_button_border.cc50
-rw-r--r--chromium/ui/views/controls/button/label_button_unittest.cc53
-rw-r--r--chromium/ui/views/controls/button/menu_button.cc62
-rw-r--r--chromium/ui/views/controls/button/menu_button.h18
-rw-r--r--chromium/ui/views/controls/button/menu_button_unittest.cc199
-rw-r--r--chromium/ui/views/controls/button/radio_button.cc10
-rw-r--r--chromium/ui/views/controls/button/radio_button.h6
-rw-r--r--chromium/ui/views/controls/button/text_button.cc185
-rw-r--r--chromium/ui/views/controls/button/text_button.h72
-rw-r--r--chromium/ui/views/controls/combobox/combobox.cc244
-rw-r--r--chromium/ui/views/controls/combobox/combobox.h53
-rw-r--r--chromium/ui/views/controls/combobox/combobox_listener.h21
-rw-r--r--chromium/ui/views/controls/combobox/combobox_unittest.cc244
-rw-r--r--chromium/ui/views/controls/image_view.cc42
-rw-r--r--chromium/ui/views/controls/image_view.h16
-rw-r--r--chromium/ui/views/controls/label.cc261
-rw-r--r--chromium/ui/views/controls/label.h169
-rw-r--r--chromium/ui/views/controls/label_unittest.cc477
-rw-r--r--chromium/ui/views/controls/link.cc115
-rw-r--r--chromium/ui/views/controls/link.h26
-rw-r--r--chromium/ui/views/controls/menu/display_change_listener_mac.cc16
-rw-r--r--chromium/ui/views/controls/menu/menu.cc26
-rw-r--r--chromium/ui/views/controls/menu/menu.h30
-rw-r--r--chromium/ui/views/controls/menu/menu_config.cc13
-rw-r--r--chromium/ui/views/controls/menu/menu_config.h17
-rw-r--r--chromium/ui/views/controls/menu/menu_config_aura.cc (renamed from chromium/ui/views/controls/menu/menu_config_views.cc)8
-rw-r--r--chromium/ui/views/controls/menu/menu_config_mac.cc26
-rw-r--r--chromium/ui/views/controls/menu/menu_config_win.cc21
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc376
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.h63
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_aura.cc115
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc267
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_win.cc27
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.cc29
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.h34
-rw-r--r--chromium/ui/views/controls/menu/menu_event_dispatcher_linux.cc91
-rw-r--r--chromium/ui/views/controls/menu/menu_event_dispatcher_linux.h32
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc20
-rw-r--r--chromium/ui/views/controls/menu/menu_host_root_view.cc9
-rw-r--r--chromium/ui/views/controls/menu/menu_image_util.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc238
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.h98
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop.h57
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_aura.cc202
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_aura.h52
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_mac.cc51
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_mac.h35
-rw-r--r--chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc95
-rw-r--r--chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.h36
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc32
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.h7
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc11
-rw-r--r--chromium/ui/views/controls/menu/menu_runner.cc32
-rw-r--r--chromium/ui/views/controls/menu/menu_runner.h15
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_handler.h4
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc43
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.h11
-rw-r--r--chromium/ui/views/controls/menu/menu_separator.h6
-rw-r--r--chromium/ui/views/controls/menu/menu_separator_views.cc4
-rw-r--r--chromium/ui/views/controls/menu/menu_separator_win.cc11
-rw-r--r--chromium/ui/views/controls/menu/menu_types.h26
-rw-r--r--chromium/ui/views/controls/menu/menu_win.cc572
-rw-r--r--chromium/ui/views/controls/menu/menu_win.h139
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.cc40
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.h4
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.cc68
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.h30
-rw-r--r--chromium/ui/views/controls/message_box_view.cc43
-rw-r--r--chromium/ui/views/controls/message_box_view.h14
-rw-r--r--chromium/ui/views/controls/native/native_view_host.cc20
-rw-r--r--chromium/ui/views/controls/native/native_view_host.h6
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.cc7
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.h1
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura_unittest.cc19
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac.cc18
-rw-r--r--chromium/ui/views/controls/native/native_view_host_unittest.cc15
-rw-r--r--chromium/ui/views/controls/native/native_view_host_win.cc157
-rw-r--r--chromium/ui/views/controls/native/native_view_host_win.h47
-rw-r--r--chromium/ui/views/controls/native/native_view_host_wrapper.h4
-rw-r--r--chromium/ui/views/controls/native_control.cc389
-rw-r--r--chromium/ui/views/controls/native_control.h126
-rw-r--r--chromium/ui/views/controls/native_control_win.cc226
-rw-r--r--chromium/ui/views/controls/native_control_win.h99
-rw-r--r--chromium/ui/views/controls/prefix_delegate.h2
-rw-r--r--chromium/ui/views/controls/prefix_selector.cc25
-rw-r--r--chromium/ui/views/controls/prefix_selector.h15
-rw-r--r--chromium/ui/views/controls/prefix_selector_unittest.cc6
-rw-r--r--chromium/ui/views/controls/progress_bar.cc21
-rw-r--r--chromium/ui/views/controls/progress_bar.h10
-rw-r--r--chromium/ui/views/controls/progress_bar_unittest.cc16
-rw-r--r--chromium/ui/views/controls/resize_area.cc22
-rw-r--r--chromium/ui/views/controls/resize_area.h2
-rw-r--r--chromium/ui/views/controls/scroll_view.cc54
-rw-r--r--chromium/ui/views/controls/scroll_view.h15
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc103
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar.cc39
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar.h10
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc5
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.cc309
-rw-r--r--chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.h91
-rw-r--r--chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc6
-rw-r--r--chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar.cc7
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc10
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc16
-rw-r--r--chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/scroll_bar.cc6
-rw-r--r--chromium/ui/views/controls/scrollbar/scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc11
-rw-r--r--chromium/ui/views/controls/separator.cc10
-rw-r--r--chromium/ui/views/controls/separator.h7
-rw-r--r--chromium/ui/views/controls/single_split_view.cc28
-rw-r--r--chromium/ui/views/controls/single_split_view.h8
-rw-r--r--chromium/ui/views/controls/single_split_view_listener.h4
-rw-r--r--chromium/ui/views/controls/single_split_view_unittest.cc58
-rw-r--r--chromium/ui/views/controls/slide_out_view.cc26
-rw-r--r--chromium/ui/views/controls/slider.cc77
-rw-r--r--chromium/ui/views/controls/slider.h26
-rw-r--r--chromium/ui/views/controls/slider_unittest.cc382
-rw-r--r--chromium/ui/views/controls/styled_label.cc147
-rw-r--r--chromium/ui/views/controls/styled_label.h29
-rw-r--r--chromium/ui/views/controls/styled_label_unittest.cc161
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc42
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.h8
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h4
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc4
-rw-r--r--chromium/ui/views/controls/table/table_grouper.h6
-rw-r--r--chromium/ui/views/controls/table/table_header.cc33
-rw-r--r--chromium/ui/views/controls/table/table_header.h8
-rw-r--r--chromium/ui/views/controls/table/table_utils.cc25
-rw-r--r--chromium/ui/views/controls/table/table_utils.h18
-rw-r--r--chromium/ui/views/controls/table/table_utils_unittest.cc70
-rw-r--r--chromium/ui/views/controls/table/table_view.cc31
-rw-r--r--chromium/ui/views/controls/table/table_view.h10
-rw-r--r--chromium/ui/views/controls/table/table_view_observer.h3
-rw-r--r--chromium/ui/views/controls/table/table_view_unittest.cc23
-rw-r--r--chromium/ui/views/controls/table/test_table_model.cc6
-rw-r--r--chromium/ui/views/controls/table/test_table_model.h2
-rw-r--r--chromium/ui/views/controls/textfield/native_textfield_views.cc1545
-rw-r--r--chromium/ui/views/controls/textfield/native_textfield_views.h345
-rw-r--r--chromium/ui/views/controls/textfield/native_textfield_wrapper.h188
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc1817
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h450
-rw-r--r--chromium/ui/views/controls/textfield/textfield_controller.cc16
-rw-r--r--chromium/ui/views/controls/textfield/textfield_controller.h24
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.cc (renamed from chromium/ui/views/controls/textfield/textfield_views_model.cc)336
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.h (renamed from chromium/ui/views/controls/textfield/textfield_views_model.h)157
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model_unittest.cc (renamed from chromium/ui/views/controls/textfield/textfield_views_model_unittest.cc)808
-rw-r--r--chromium/ui/views/controls/textfield/textfield_test_api.cc30
-rw-r--r--chromium/ui/views/controls/textfield/textfield_test_api.h43
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc (renamed from chromium/ui/views/controls/textfield/native_textfield_views_unittest.cc)1080
-rw-r--r--chromium/ui/views/controls/throbber.cc2
-rw-r--r--chromium/ui/views/controls/throbber.h2
-rw-r--r--chromium/ui/views/controls/tree/tree_view.cc44
-rw-r--r--chromium/ui/views/controls/tree/tree_view.h21
-rw-r--r--chromium/ui/views/controls/tree/tree_view_unittest.cc14
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc4
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.cc44
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.h20
-rw-r--r--chromium/ui/views/controls/webview/webview.cc236
-rw-r--r--chromium/ui/views/controls/webview/webview.gyp3
-rw-r--r--chromium/ui/views/controls/webview/webview.h51
-rw-r--r--chromium/ui/views/controls/webview/webview_interactive_uitest.cc82
-rw-r--r--chromium/ui/views/controls/webview/webview_tests.gyp38
182 files changed, 7893 insertions, 8764 deletions
diff --git a/chromium/ui/views/controls/button/blue_button.cc b/chromium/ui/views/controls/button/blue_button.cc
index 3e52afd896e..e3a9487ff6c 100644
--- a/chromium/ui/views/controls/button/blue_button.cc
+++ b/chromium/ui/views/controls/button/blue_button.cc
@@ -5,19 +5,13 @@
#include "ui/views/controls/button/blue_button.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/sys_color_change_listener.h"
#include "ui/views/controls/button/label_button_border.h"
namespace {
-// Insets for the unified blue_button images. This assumes that the images
-// are of a 9 grid, of 5x5 size each.
-const int kBlueButtonInsets = 5;
-
-// Default text and shadow colors for the blue button.
-const SkColor kBlueButtonTextColor = SK_ColorWHITE;
+// Default shadow color for the blue button.
const SkColor kBlueButtonShadowColor = SkColorSetRGB(0x53, 0x8C, 0xEA);
} // namespace
@@ -27,42 +21,11 @@ namespace views {
// static
const char BlueButton::kViewClassName[] = "views/BlueButton";
-BlueButton::BlueButton(ButtonListener* listener, const string16& text)
+BlueButton::BlueButton(ButtonListener* listener, const base::string16& text)
: LabelButton(listener, text) {
// Inherit STYLE_BUTTON insets, minimum size, alignment, etc.
SetStyle(STYLE_BUTTON);
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- const gfx::Insets insets(kBlueButtonInsets,
- kBlueButtonInsets,
- kBlueButtonInsets,
- kBlueButtonInsets);
-
- LabelButtonBorder* button_border = static_cast<LabelButtonBorder*>(border());
- button_border->SetPainter(false, STATE_NORMAL,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_NORMAL), insets));
- button_border->SetPainter(false, STATE_HOVERED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_HOVER), insets));
- button_border->SetPainter(false, STATE_PRESSED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_PRESSED), insets));
- button_border->SetPainter(false, STATE_DISABLED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
- button_border->SetPainter(true, STATE_NORMAL,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_NORMAL), insets));
- button_border->SetPainter(true, STATE_HOVERED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_HOVER), insets));
- button_border->SetPainter(true, STATE_PRESSED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_PRESSED), insets));
- button_border->SetPainter(true, STATE_DISABLED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
+ UpdateThemedBorder();
}
BlueButton::~BlueButton() {}
@@ -70,10 +33,18 @@ BlueButton::~BlueButton() {}
void BlueButton::ResetColorsFromNativeTheme() {
LabelButton::ResetColorsFromNativeTheme();
if (!gfx::IsInvertedColorScheme()) {
- for (size_t state = STATE_NORMAL; state < STATE_COUNT; ++state)
- SetTextColor(static_cast<ButtonState>(state), kBlueButtonTextColor);
- label()->SetShadowColors(kBlueButtonShadowColor, kBlueButtonShadowColor);
- label()->SetShadowOffset(0, 1);
+ SetTextColor(STATE_NORMAL, GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_BlueButtonEnabledColor));
+ SetTextColor(STATE_HOVERED, GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_BlueButtonHoverColor));
+ SetTextColor(STATE_PRESSED, GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_BlueButtonHighlightColor));
+ SetTextColor(STATE_DISABLED, GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_BlueButtonDisabledColor));
+
+ // TODO(estade): this is not great on system themes.
+ label()->set_shadows(gfx::ShadowValues(1,
+ gfx::ShadowValue(gfx::Point(0, 1), 0, kBlueButtonShadowColor)));
}
}
@@ -81,4 +52,28 @@ const char* BlueButton::GetClassName() const {
return BlueButton::kViewClassName;
}
+scoped_ptr<LabelButtonBorder> BlueButton::CreateDefaultBorder() const {
+ // Insets for splitting the images.
+ const gfx::Insets insets(5, 5, 5, 5);
+ scoped_ptr<LabelButtonBorder> button_border(new LabelButtonBorder(style()));
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ button_border->SetPainter(false, STATE_NORMAL, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_NORMAL), insets));
+ button_border->SetPainter(false, STATE_HOVERED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_HOVER), insets));
+ button_border->SetPainter(false, STATE_PRESSED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_PRESSED), insets));
+ button_border->SetPainter(false, STATE_DISABLED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
+ button_border->SetPainter(true, STATE_NORMAL, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_NORMAL), insets));
+ button_border->SetPainter(true, STATE_HOVERED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_HOVER), insets));
+ button_border->SetPainter(true, STATE_PRESSED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_PRESSED), insets));
+ button_border->SetPainter(true, STATE_DISABLED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
+ return button_border.Pass();
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/button/blue_button.h b/chromium/ui/views/controls/button/blue_button.h
index a169fba85d1..8c83c007ec6 100644
--- a/chromium/ui/views/controls/button/blue_button.h
+++ b/chromium/ui/views/controls/button/blue_button.h
@@ -22,6 +22,7 @@ class VIEWS_EXPORT BlueButton : public LabelButton {
// Overridden from LabelButton:
virtual void ResetColorsFromNativeTheme() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
+ virtual scoped_ptr<LabelButtonBorder> CreateDefaultBorder() const OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(BlueButton);
};
diff --git a/chromium/ui/views/controls/button/blue_button_unittest.cc b/chromium/ui/views/controls/button/blue_button_unittest.cc
new file mode 100644
index 00000000000..908e747d24c
--- /dev/null
+++ b/chromium/ui/views/controls/button/blue_button_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/button/blue_button.h"
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/views/controls/button/label_button_border.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace views {
+
+namespace {
+
+class TestBlueButton : public BlueButton {
+ public:
+ TestBlueButton() : BlueButton(NULL, base::ASCIIToUTF16("foo")) {}
+ virtual ~TestBlueButton() {}
+
+ using BlueButton::OnNativeThemeChanged;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestBlueButton);
+};
+
+} // namespace
+
+typedef ViewsTestBase BlueButtonTest;
+
+TEST_F(BlueButtonTest, Border) {
+ // Compared to a normal LabelButton...
+ LabelButton button(NULL, base::ASCIIToUTF16("foo"));
+ button.SetBoundsRect(gfx::Rect(gfx::Point(0, 0), button.GetPreferredSize()));
+ gfx::Canvas button_canvas(button.bounds().size(), 1.0, true);
+ button.border()->Paint(button, &button_canvas);
+
+ // ... a special blue border should be used.
+ TestBlueButton blue_button;
+ blue_button.SetBoundsRect(gfx::Rect(gfx::Point(0, 0),
+ blue_button.GetPreferredSize()));
+ gfx::Canvas canvas(blue_button.bounds().size(), 1.0, true);
+ blue_button.border()->Paint(blue_button, &canvas);
+ EXPECT_EQ(button.GetText(), blue_button.GetText());
+ EXPECT_FALSE(gfx::BitmapsAreEqual(button_canvas.ExtractImageRep().sk_bitmap(),
+ canvas.ExtractImageRep().sk_bitmap()));
+
+ // Make sure it's still used after the native theme "changes".
+ blue_button.OnNativeThemeChanged(NULL);
+ gfx::Canvas canvas2(blue_button.bounds().size(), 1.0, true);
+ blue_button.border()->Paint(blue_button, &canvas2);
+
+ EXPECT_TRUE(gfx::BitmapsAreEqual(canvas.ExtractImageRep().sk_bitmap(),
+ canvas2.ExtractImageRep().sk_bitmap()));
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc
index 96e2e27432c..4e7f51b5450 100644
--- a/chromium/ui/views/controls/button/button.cc
+++ b/chromium/ui/views/controls/button/button.cc
@@ -5,31 +5,47 @@
#include "ui/views/controls/button/button.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
namespace views {
////////////////////////////////////////////////////////////////////////////////
+// Button, static public:
+
+// static
+Button::ButtonState Button::GetButtonStateFrom(ui::NativeTheme::State state) {
+ switch (state) {
+ case ui::NativeTheme::kDisabled: return Button::STATE_DISABLED;
+ case ui::NativeTheme::kHovered: return Button::STATE_HOVERED;
+ case ui::NativeTheme::kNormal: return Button::STATE_NORMAL;
+ case ui::NativeTheme::kPressed: return Button::STATE_PRESSED;
+ case ui::NativeTheme::kMaxState: NOTREACHED() << "Unknown state: " << state;
+ }
+ return Button::STATE_NORMAL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Button, public:
Button::~Button() {
}
-void Button::SetTooltipText(const string16& tooltip_text) {
+void Button::SetTooltipText(const base::string16& tooltip_text) {
tooltip_text_ = tooltip_text;
if (accessible_name_.empty())
accessible_name_ = tooltip_text_;
TooltipTextChanged();
}
-void Button::SetAccessibleName(const string16& name) {
+void Button::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
////////////////////////////////////////////////////////////////////////////////
// Button, View overrides:
-bool Button::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool Button::GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const {
if (tooltip_text_.empty())
return false;
@@ -37,8 +53,8 @@ bool Button::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
return true;
}
-void Button::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
+void Button::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_BUTTON;
state->name = accessible_name_;
}
diff --git a/chromium/ui/views/controls/button/button.h b/chromium/ui/views/controls/button/button.h
index d038015f870..37d639dd6a8 100644
--- a/chromium/ui/views/controls/button/button.h
+++ b/chromium/ui/views/controls/button/button.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_CONTROLS_BUTTON_BUTTON_H_
#define UI_VIEWS_CONTROLS_BUTTON_BUTTON_H_
+#include "ui/native_theme/native_theme.h"
#include "ui/views/view.h"
namespace views {
@@ -42,21 +43,22 @@ class VIEWS_EXPORT Button : public View {
enum ButtonStyle {
STYLE_BUTTON = 0,
STYLE_TEXTBUTTON,
- STYLE_NATIVE_TEXTBUTTON,
STYLE_COUNT,
};
- void SetTooltipText(const string16& tooltip_text);
+ static ButtonState GetButtonStateFrom(ui::NativeTheme::State state);
+
+ void SetTooltipText(const base::string16& tooltip_text);
int tag() const { return tag_; }
void set_tag(int tag) { tag_ = tag; }
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
// Overridden from View:
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// Construct the Button with a Listener. The listener can be NULL. This can be
@@ -72,10 +74,10 @@ class VIEWS_EXPORT Button : public View {
private:
// The text shown in a tooltip.
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
// Accessibility data.
- string16 accessible_name_;
+ base::string16 accessible_name_;
// The id tag associated with this button. Used to disambiguate buttons in
// the ButtonListener implementation.
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index ec33a47e2b1..22c5f88e2d6 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -5,7 +5,7 @@
#include "ui/views/controls/button/checkbox.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/painter.h"
@@ -15,15 +15,16 @@ namespace views {
// static
const char Checkbox::kViewClassName[] = "Checkbox";
-Checkbox::Checkbox(const string16& label)
+Checkbox::Checkbox(const base::string16& label)
: LabelButton(NULL, label),
checked_(false) {
SetHorizontalAlignment(gfx::ALIGN_LEFT);
- LabelButtonBorder* button_border = static_cast<LabelButtonBorder*>(border());
+ scoped_ptr<LabelButtonBorder> button_border(new LabelButtonBorder(style()));
button_border->SetPainter(false, STATE_HOVERED, NULL);
button_border->SetPainter(false, STATE_PRESSED, NULL);
// Inset the trailing side by a couple pixels for the focus border.
button_border->set_insets(gfx::Insets(0, 0, 0, 2));
+ SetBorder(button_border.PassAs<Border>());
SetFocusable(true);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
@@ -93,10 +94,11 @@ const char* Checkbox::GetClassName() const {
return kViewClassName;
}
-void Checkbox::GetAccessibleState(ui::AccessibleViewState* state) {
+void Checkbox::GetAccessibleState(ui::AXViewState* state) {
LabelButton::GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_CHECKBUTTON;
- state->state = checked() ? ui::AccessibilityTypes::STATE_CHECKED : 0;
+ state->role = ui::AX_ROLE_CHECK_BOX;
+ if (checked())
+ state->AddStateFlag(ui::AX_STATE_CHECKED);
}
void Checkbox::OnFocus() {
diff --git a/chromium/ui/views/controls/button/checkbox.h b/chromium/ui/views/controls/button/checkbox.h
index a603bd5b2dd..7bfd5bcf7d1 100644
--- a/chromium/ui/views/controls/button/checkbox.h
+++ b/chromium/ui/views/controls/button/checkbox.h
@@ -19,7 +19,7 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
public:
static const char kViewClassName[];
- explicit Checkbox(const string16& label);
+ explicit Checkbox(const base::string16& label);
virtual ~Checkbox();
// Sets a listener for this checkbox. Checkboxes aren't required to have them
@@ -34,7 +34,7 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
// Overridden from LabelButton:
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
virtual const gfx::ImageSkia& GetImage(ButtonState for_state) OVERRIDE;
diff --git a/chromium/ui/views/controls/button/custom_button.cc b/chromium/ui/views/controls/button/custom_button.cc
index 2be2a2301e1..0e237a31273 100644
--- a/chromium/ui/views/controls/button/custom_button.cc
+++ b/chromium/ui/views/controls/button/custom_button.cc
@@ -4,7 +4,7 @@
#include "ui/views/controls/button/custom_button.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/animation/throb_animation.h"
@@ -101,7 +101,7 @@ void CustomButton::SetHotTracked(bool is_hot_tracked) {
SetState(is_hot_tracked ? STATE_HOVERED : STATE_NORMAL);
if (is_hot_tracked)
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
bool CustomButton::IsHotTracked() const {
@@ -199,6 +199,7 @@ bool CustomButton::OnKeyPressed(const ui::KeyEvent& event) {
ui::MouseEvent synthetic_event(ui::ET_MOUSE_RELEASED,
gfx::Point(),
gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
NotifyClick(synthetic_event);
} else {
@@ -216,6 +217,7 @@ bool CustomButton::OnKeyReleased(const ui::KeyEvent& event) {
ui::MouseEvent synthetic_event(ui::ET_MOUSE_RELEASED,
gfx::Point(),
gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
NotifyClick(synthetic_event);
return true;
@@ -260,6 +262,7 @@ bool CustomButton::AcceleratorPressed(const ui::Accelerator& accelerator) {
ui::MouseEvent synthetic_event(ui::ET_MOUSE_RELEASED,
gfx::Point(),
gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
NotifyClick(synthetic_event);
return true;
@@ -281,17 +284,17 @@ void CustomButton::OnDragDone() {
SetState(STATE_NORMAL);
}
-void CustomButton::GetAccessibleState(ui::AccessibleViewState* state) {
+void CustomButton::GetAccessibleState(ui::AXViewState* state) {
Button::GetAccessibleState(state);
switch (state_) {
case STATE_HOVERED:
- state->state = ui::AccessibilityTypes::STATE_HOTTRACKED;
+ state->AddStateFlag(ui::AX_STATE_HOVERED);
break;
case STATE_PRESSED:
- state->state = ui::AccessibilityTypes::STATE_PRESSED;
+ state->AddStateFlag(ui::AX_STATE_PRESSED);
break;
case STATE_DISABLED:
- state->state = ui::AccessibilityTypes::STATE_UNAVAILABLE;
+ state->AddStateFlag(ui::AX_STATE_DISABLED);
break;
case STATE_NORMAL:
case STATE_COUNT:
diff --git a/chromium/ui/views/controls/button/custom_button.h b/chromium/ui/views/controls/button/custom_button.h
index 9ac502d3d96..4614a5c7323 100644
--- a/chromium/ui/views/controls/button/custom_button.h
+++ b/chromium/ui/views/controls/button/custom_button.h
@@ -18,8 +18,8 @@ namespace views {
class CustomButtonStateChangedDelegate;
-// A button with custom rendering. The common base class of ImageButton and
-// TextButton.
+// A button with custom rendering. The common base class of ImageButton,
+// LabelButton and TextButton.
// Note that this type of button is not focusable by default and will not be
// part of the focus chain. Call SetFocusable(true) to make it part of the
// focus chain.
@@ -84,7 +84,7 @@ class VIEWS_EXPORT CustomButton : public Button,
virtual void ShowContextMenu(const gfx::Point& p,
ui::MenuSourceType source_type) OVERRIDE;
virtual void OnDragDone() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
// Overridden from gfx::AnimationDelegate:
diff --git a/chromium/ui/views/controls/button/custom_button_unittest.cc b/chromium/ui/views/controls/button/custom_button_unittest.cc
index f7b11e648ed..84836716701 100644
--- a/chromium/ui/views/controls/button/custom_button_unittest.cc
+++ b/chromium/ui/views/controls/button/custom_button_unittest.cc
@@ -5,6 +5,9 @@
#include "ui/views/controls/button/custom_button.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/test_cursor_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/layout.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/button/checkbox.h"
@@ -16,12 +19,6 @@
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
-#if defined(USE_AURA)
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/test_cursor_client.h"
-#include "ui/aura/window.h"
-#endif
-
namespace views {
namespace {
@@ -38,7 +35,6 @@ class TestCustomButton : public CustomButton {
DISALLOW_COPY_AND_ASSIGN(TestCustomButton);
};
-#if defined(USE_AURA)
void PerformGesture(CustomButton* button, ui::EventType event_type) {
ui::GestureEventDetails gesture_details(event_type, 0, 0);
base::TimeDelta time_stamp = base::TimeDelta::FromMicroseconds(0);
@@ -46,7 +42,6 @@ void PerformGesture(CustomButton* button, ui::EventType event_type) {
gesture_details, 1);
button->OnGestureEvent(&gesture_event);
}
-#endif // USE_AURA
} // namespace
@@ -63,10 +58,8 @@ TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
widget->Init(params);
widget->Show();
-#if defined(USE_AURA)
aura::test::TestCursorClient cursor_client(
widget->GetNativeView()->GetRootWindow());
-#endif
// Position the widget in a way so that it is under the cursor.
gfx::Point cursor = gfx::Screen::GetScreenFor(
@@ -80,10 +73,12 @@ TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
gfx::Point center(10, 10);
button->OnMousePressed(ui::MouseEvent(ui::ET_MOUSE_PRESSED, center, center,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_EQ(CustomButton::STATE_PRESSED, button->state());
button->OnMouseReleased(ui::MouseEvent(ui::ET_MOUSE_RELEASED, center, center,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_EQ(CustomButton::STATE_HOVERED, button->state());
@@ -99,7 +94,6 @@ TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
button->SetVisible(true);
EXPECT_EQ(CustomButton::STATE_HOVERED, button->state());
-#if defined(USE_AURA)
// In Aura views, no new hover effects are invoked if mouse events
// are disabled.
cursor_client.DisableMouseEvents();
@@ -115,10 +109,8 @@ TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
button->SetVisible(true);
EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
-#endif
}
-#if defined(USE_AURA)
// Tests that gesture events correctly change the button state.
TEST_F(CustomButtonTest, GestureEventsSetState) {
// Create a widget so that the CustomButton can query the hover state
@@ -148,12 +140,10 @@ TEST_F(CustomButtonTest, GestureEventsSetState) {
EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
}
-#endif // USE_AURA
-
// Make sure all subclasses of CustomButton are correctly recognized
// as CustomButton.
TEST_F(CustomButtonTest, AsCustomButton) {
- string16 text;
+ base::string16 text;
TextButton text_button(NULL, text);
EXPECT_TRUE(CustomButton::AsCustomButton(&text_button));
@@ -176,7 +166,7 @@ TEST_F(CustomButtonTest, AsCustomButton) {
Link link(text);
EXPECT_FALSE(CustomButton::AsCustomButton(&link));
- Textfield textfield(Textfield::STYLE_DEFAULT);
+ Textfield textfield;
EXPECT_FALSE(CustomButton::AsCustomButton(&textfield));
}
diff --git a/chromium/ui/views/controls/button/image_button.cc b/chromium/ui/views/controls/button/image_button.cc
index 6a842346d2c..ecbd4a10724 100644
--- a/chromium/ui/views/controls/button/image_button.cc
+++ b/chromium/ui/views/controls/button/image_button.cc
@@ -5,7 +5,7 @@
#include "ui/views/controls/button/image_button.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/animation/throb_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia_operations.h"
@@ -60,14 +60,6 @@ void ImageButton::SetBackground(SkColor color,
*image, *mask);
}
-void ImageButton::SetOverlayImage(const gfx::ImageSkia* image) {
- if (!image) {
- overlay_image_ = gfx::ImageSkia();
- return;
- }
- overlay_image_ = *image;
-}
-
void ImageButton::SetImageAlignment(HorizontalAlignment h_align,
VerticalAlignment v_align) {
h_alignment_ = h_align;
@@ -82,7 +74,7 @@ void ImageButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
////////////////////////////////////////////////////////////////////////////////
// ImageButton, View overrides:
-gfx::Size ImageButton::GetPreferredSize() {
+gfx::Size ImageButton::GetPreferredSize() const {
gfx::Size size = preferred_size_;
if (!images_[STATE_NORMAL].isNull()) {
size = gfx::Size(images_[STATE_NORMAL].width(),
@@ -116,9 +108,6 @@ void ImageButton::OnPaint(gfx::Canvas* canvas) {
canvas->DrawImageInt(background_image_, position.x(), position.y());
canvas->DrawImageInt(img, position.x(), position.y());
-
- if (!overlay_image_.isNull())
- canvas->DrawImageInt(overlay_image_, position.x(), position.y());
}
Painter::PaintFocusPainter(this, canvas, focus_painter());
@@ -206,7 +195,7 @@ void ToggleImageButton::SetToggled(bool toggled) {
toggled_ = toggled;
SchedulePaint();
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true);
}
void ToggleImageButton::SetToggledImage(ButtonState state,
@@ -220,7 +209,7 @@ void ToggleImageButton::SetToggledImage(ButtonState state,
}
}
-void ToggleImageButton::SetToggledTooltipText(const string16& tooltip) {
+void ToggleImageButton::SetToggledTooltipText(const base::string16& tooltip) {
toggled_tooltip_text_ = tooltip;
}
@@ -249,7 +238,7 @@ void ToggleImageButton::SetImage(ButtonState state,
// ToggleImageButton, View overrides:
bool ToggleImageButton::GetTooltipText(const gfx::Point& p,
- string16* tooltip) const {
+ base::string16* tooltip) const {
if (!toggled_ || toggled_tooltip_text_.empty())
return Button::GetTooltipText(p, tooltip);
@@ -257,7 +246,7 @@ bool ToggleImageButton::GetTooltipText(const gfx::Point& p,
return true;
}
-void ToggleImageButton::GetAccessibleState(ui::AccessibleViewState* state) {
+void ToggleImageButton::GetAccessibleState(ui::AXViewState* state) {
ImageButton::GetAccessibleState(state);
GetTooltipText(gfx::Point(), &state->name);
}
diff --git a/chromium/ui/views/controls/button/image_button.h b/chromium/ui/views/controls/button/image_button.h
index 4977b06d398..fc02b8ac9ce 100644
--- a/chromium/ui/views/controls/button/image_button.h
+++ b/chromium/ui/views/controls/button/image_button.h
@@ -51,10 +51,6 @@ class VIEWS_EXPORT ImageButton : public CustomButton {
const gfx::ImageSkia* image,
const gfx::ImageSkia* mask);
- // Set an |image| to draw on top of the normal / hot / pushed image.
- // Pass NULL for no image.
- void SetOverlayImage(const gfx::ImageSkia* image);
-
// Sets how the image is laid out within the button's bounds.
void SetImageAlignment(HorizontalAlignment h_align,
VerticalAlignment v_align);
@@ -73,7 +69,7 @@ class VIEWS_EXPORT ImageButton : public CustomButton {
}
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
@@ -96,9 +92,6 @@ class VIEWS_EXPORT ImageButton : public CustomButton {
gfx::ImageSkia background_image_;
- // Image to draw on top of normal / hot / pushed image. Usually empty.
- gfx::ImageSkia overlay_image_;
-
private:
FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, Basics);
FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, ImagePositionWithBorder);
@@ -145,7 +138,7 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
void SetToggledImage(ButtonState state, const gfx::ImageSkia* image);
// Set the tooltip text displayed when the button is toggled.
- void SetToggledTooltipText(const string16& tooltip);
+ void SetToggledTooltipText(const base::string16& tooltip);
// Overridden from ImageButton:
virtual const gfx::ImageSkia& GetImage(ButtonState state) const OVERRIDE;
@@ -154,8 +147,8 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
// Overridden from View:
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
private:
// The parent class's images_ member is used for the current images,
@@ -168,7 +161,7 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
// The parent class's tooltip_text_ is displayed when not toggled, and
// this one is shown when toggled.
- string16 toggled_tooltip_text_;
+ base::string16 toggled_tooltip_text_;
DISALLOW_COPY_AND_ASSIGN(ToggleImageButton);
};
diff --git a/chromium/ui/views/controls/button/image_button_unittest.cc b/chromium/ui/views/controls/button/image_button_unittest.cc
index 995b2056de4..406d02c3ae2 100644
--- a/chromium/ui/views/controls/button/image_button_unittest.cc
+++ b/chromium/ui/views/controls/button/image_button_unittest.cc
@@ -60,25 +60,6 @@ TEST_F(ImageButtonTest, Basics) {
EXPECT_FALSE(button.GetImageToPaint().isNull());
EXPECT_EQ(10, button.GetImageToPaint().width());
EXPECT_EQ(20, button.GetImageToPaint().height());
-
- // Set an overlay image.
- gfx::ImageSkia overlay_image = CreateTestImage(12, 22);
- button.SetOverlayImage(&overlay_image);
- EXPECT_EQ(12, button.overlay_image_.width());
- EXPECT_EQ(22, button.overlay_image_.height());
-
- // By convention, preferred size doesn't change, even though pushed image
- // is bigger.
- EXPECT_EQ("10x20", button.GetPreferredSize().ToString());
-
- // We're still painting the normal image.
- EXPECT_FALSE(button.GetImageToPaint().isNull());
- EXPECT_EQ(10, button.GetImageToPaint().width());
- EXPECT_EQ(20, button.GetImageToPaint().height());
-
- // Reset the overlay image.
- button.SetOverlayImage(NULL);
- EXPECT_TRUE(button.overlay_image_.isNull());
}
TEST_F(ImageButtonTest, SetAndGetImage) {
@@ -116,11 +97,11 @@ TEST_F(ImageButtonTest, ImagePositionWithBorder) {
EXPECT_EQ(gfx::Point().ToString(),
button.ComputeImagePaintPosition(image).ToString());
- button.set_border(views::Border::CreateEmptyBorder(10, 5, 0, 0));
+ button.SetBorder(views::Border::CreateEmptyBorder(10, 5, 0, 0));
EXPECT_EQ(gfx::Point(5, 10).ToString(),
button.ComputeImagePaintPosition(image).ToString());
- button.set_border(NULL);
+ button.SetBorder(Border::NullBorder());
button.SetBounds(0, 0, 50, 50);
EXPECT_EQ(gfx::Point().ToString(),
button.ComputeImagePaintPosition(image).ToString());
@@ -129,7 +110,7 @@ TEST_F(ImageButtonTest, ImagePositionWithBorder) {
ImageButton::ALIGN_MIDDLE);
EXPECT_EQ(gfx::Point(15, 10).ToString(),
button.ComputeImagePaintPosition(image).ToString());
- button.set_border(views::Border::CreateEmptyBorder(10, 10, 0, 0));
+ button.SetBorder(views::Border::CreateEmptyBorder(10, 10, 0, 0));
EXPECT_EQ(gfx::Point(20, 15).ToString(),
button.ComputeImagePaintPosition(image).ToString());
}
diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc
index 30db5d13d9a..c0399147775 100644
--- a/chromium/ui/views/controls/button/label_button.cc
+++ b/chromium/ui/views/controls/button/label_button.cc
@@ -8,14 +8,17 @@
#include "grit/ui_resources.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/animation/throb_animation.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/sys_color_change_listener.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/background.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/painter.h"
#include "ui/views/window/dialog_delegate.h"
-#if defined(OS_WIN)
-#include "ui/native_theme/native_theme_win.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/views/linux_ui/linux_ui.h"
#endif
namespace {
@@ -23,9 +26,11 @@ namespace {
// The spacing between the icon and text.
const int kSpacing = 5;
+#if !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
// Default text and shadow colors for STYLE_BUTTON.
const SkColor kStyleButtonTextColor = SK_ColorBLACK;
const SkColor kStyleButtonShadowColor = SK_ColorWHITE;
+#endif
} // namespace
@@ -37,7 +42,7 @@ const int LabelButton::kHoverAnimationDurationMs = 170;
// static
const char LabelButton::kViewClassName[] = "LabelButton";
-LabelButton::LabelButton(ButtonListener* listener, const string16& text)
+LabelButton::LabelButton(ButtonListener* listener, const base::string16& text)
: CustomButton(listener),
image_(new ImageView()),
label_(new Label()),
@@ -45,9 +50,11 @@ LabelButton::LabelButton(ButtonListener* listener, const string16& text)
button_state_colors_(),
explicitly_set_colors_(),
is_default_(false),
- style_(STYLE_TEXTBUTTON) {
+ style_(STYLE_TEXTBUTTON),
+ border_is_themed_border_(true) {
SetAnimationDuration(kHoverAnimationDurationMs);
SetText(text);
+ SetFontList(gfx::FontList());
AddChildView(image_);
image_->set_interactive(false);
@@ -75,11 +82,11 @@ void LabelButton::SetImage(ButtonState for_state, const gfx::ImageSkia& image) {
UpdateImage();
}
-const string16& LabelButton::GetText() const {
+const base::string16& LabelButton::GetText() const {
return label_->text();
}
-void LabelButton::SetText(const string16& text) {
+void LabelButton::SetText(const base::string16& text) {
SetAccessibleName(text);
label_->SetText(text);
}
@@ -93,6 +100,14 @@ void LabelButton::SetTextColor(ButtonState for_state, SkColor color) {
explicitly_set_colors_[for_state] = true;
}
+void LabelButton::SetTextShadows(const gfx::ShadowValues& shadows) {
+ label_->set_shadows(shadows);
+}
+
+void LabelButton::SetTextSubpixelRenderingEnabled(bool enabled) {
+ label_->set_subpixel_rendering_enabled(enabled);
+}
+
bool LabelButton::GetTextMultiLine() const {
return label_->is_multi_line();
}
@@ -101,20 +116,27 @@ void LabelButton::SetTextMultiLine(bool text_multi_line) {
label_->SetMultiLine(text_multi_line);
}
-const gfx::Font& LabelButton::GetFont() const {
- return label_->font();
+const gfx::FontList& LabelButton::GetFontList() const {
+ return label_->font_list();
}
-void LabelButton::SetFont(const gfx::Font& font) {
- label_->SetFont(font);
+void LabelButton::SetFontList(const gfx::FontList& font_list) {
+ cached_normal_font_list_ = font_list;
+ cached_bold_font_list_ = font_list.DeriveWithStyle(
+ font_list.GetFontStyle() | gfx::Font::BOLD);
+
+ // STYLE_BUTTON uses bold text to indicate default buttons.
+ label_->SetFontList(
+ style_ == STYLE_BUTTON && is_default_ ?
+ cached_bold_font_list_ : cached_normal_font_list_);
}
-void LabelButton::SetElideBehavior(Label::ElideBehavior elide_behavior) {
+void LabelButton::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
label_->SetElideBehavior(elide_behavior);
}
gfx::HorizontalAlignment LabelButton::GetHorizontalAlignment() const {
- return label_->horizontal_alignment();
+ return label_->GetHorizontalAlignment();
}
void LabelButton::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
@@ -122,6 +144,10 @@ void LabelButton::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
InvalidateLayout();
}
+void LabelButton::SetDirectionalityMode(gfx::DirectionalityMode mode) {
+ label_->set_directionality_mode(mode);
+}
+
void LabelButton::SetIsDefault(bool is_default) {
if (is_default == is_default_)
return;
@@ -131,20 +157,13 @@ void LabelButton::SetIsDefault(bool is_default) {
// STYLE_BUTTON uses bold text to indicate default buttons.
if (style_ == STYLE_BUTTON) {
- int style = label_->font().GetStyle();
- style = is_default ? style | gfx::Font::BOLD : style & ~gfx::Font::BOLD;
- label_->SetFont(label_->font().DeriveFont(0, style));
+ label_->SetFontList(
+ is_default ? cached_bold_font_list_ : cached_normal_font_list_);
}
}
void LabelButton::SetStyle(ButtonStyle style) {
- // Use the new button style instead of the native button style.
- // TODO(msw): Officialy deprecate and remove STYLE_NATIVE_TEXTBUTTON.
- if (style == STYLE_NATIVE_TEXTBUTTON)
- style = STYLE_BUTTON;
-
style_ = style;
- set_border(new LabelButtonBorder(style));
// Inset the button focus rect from the actual border; roughly match Windows.
if (style == STYLE_BUTTON) {
SetFocusPainter(scoped_ptr<Painter>());
@@ -152,34 +171,33 @@ void LabelButton::SetStyle(ButtonStyle style) {
SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(
gfx::Insets(3, 3, 3, 3)));
}
- if (style == STYLE_BUTTON || style == STYLE_NATIVE_TEXTBUTTON) {
+ if (style == STYLE_BUTTON) {
label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
SetFocusable(true);
}
if (style == STYLE_BUTTON)
set_min_size(gfx::Size(70, 33));
- // Invalidate the layout to pickup the new insets from the border.
- InvalidateLayout();
- ResetColorsFromNativeTheme();
+
+ OnNativeThemeChanged(GetNativeTheme());
}
void LabelButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
focus_painter_ = focus_painter.Pass();
}
-gfx::Size LabelButton::GetPreferredSize() {
+gfx::Size LabelButton::GetPreferredSize() const {
// Use a temporary label copy for sizing to avoid calculation side-effects.
- gfx::Font font = GetFont();
- Label label(GetText(), font);
+ Label label(GetText(), cached_normal_font_list_);
+ label.set_shadows(label_->shadows());
label.SetMultiLine(GetTextMultiLine());
if (style() == STYLE_BUTTON) {
// Some text appears wider when rendered normally than when rendered bold.
// Accommodate the widest, as buttons may show bold and shouldn't resize.
const int current_width = label.GetPreferredSize().width();
- label.SetFont(font.DeriveFont(0, font.GetStyle() ^ gfx::Font::BOLD));
+ label.SetFontList(cached_bold_font_list_);
if (label.GetPreferredSize().width() < current_width)
- label.SetFont(font);
+ label.SetFontList(cached_normal_font_list_);
}
// Resize multi-line labels given the current limited available width.
@@ -197,7 +215,7 @@ gfx::Size LabelButton::GetPreferredSize() {
size.Enlarge(image_size.width() + insets.width(), insets.height());
// Make the size at least as large as the minimum size needed by the border.
- size.SetToMax(border()->GetMinimumSize());
+ size.SetToMax(border() ? border()->GetMinimumSize() : gfx::Size());
// Increase the minimum size monotonically with the preferred size.
size.SetToMax(min_size_);
@@ -217,17 +235,17 @@ void LabelButton::Layout() {
adjusted_alignment = (adjusted_alignment == gfx::ALIGN_LEFT) ?
gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
- gfx::Rect child_area(GetLocalBounds());
+ gfx::Rect child_area(GetChildAreaBounds());
child_area.Inset(GetInsets());
gfx::Size image_size(image_->GetPreferredSize());
- image_size.set_width(std::min(image_size.width(), child_area.width()));
- image_size.set_height(std::min(image_size.height(), child_area.height()));
+ image_size.SetToMin(child_area.size());
// The label takes any remaining width after sizing the image, unless both
// views are centered. In that case, using the tighter preferred label width
// avoids wasted space within the label that would look like awkward padding.
- gfx::Size label_size(child_area.size());
+ // Labels can paint over the full button height, including the border height.
+ gfx::Size label_size(child_area.width(), height());
if (!image_size.IsEmpty() && !label_size.IsEmpty()) {
label_size.set_width(
std::max(child_area.width() - image_size.width() - kSpacing, 0));
@@ -250,8 +268,8 @@ void LabelButton::Layout() {
image_origin.Offset(child_area.width() - image_size.width(), 0);
}
- gfx::Point label_origin(child_area.origin());
- if (!image_size.IsEmpty() &&adjusted_alignment != gfx::ALIGN_RIGHT)
+ gfx::Point label_origin(child_area.x(), 0);
+ if (!image_size.IsEmpty() && adjusted_alignment != gfx::ALIGN_RIGHT)
label_origin.set_x(image_origin.x() + image_size.width() + kSpacing);
image_->SetBoundsRect(gfx::Rect(image_origin, image_size));
@@ -262,6 +280,19 @@ const char* LabelButton::GetClassName() const {
return kViewClassName;
}
+scoped_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const {
+ return scoped_ptr<LabelButtonBorder>(new LabelButtonBorder(style_));
+}
+
+void LabelButton::SetBorder(scoped_ptr<Border> border) {
+ border_is_themed_border_ = false;
+ View::SetBorder(border.Pass());
+}
+
+gfx::Rect LabelButton::GetChildAreaBounds() {
+ return GetLocalBounds();
+}
+
void LabelButton::OnPaint(gfx::Canvas* canvas) {
View::OnPaint(canvas);
Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
@@ -284,9 +315,9 @@ void LabelButton::GetExtraParams(ui::NativeTheme::ExtraParams* params) const {
params->button.indeterminate = false;
params->button.is_default = is_default_;
params->button.is_focused = HasFocus() && IsAccessibilityFocusable();
- params->button.has_border = style() == STYLE_NATIVE_TEXTBUTTON;
+ params->button.has_border = false;
params->button.classic_state = 0;
- params->button.background_color = label()->background_color();
+ params->button.background_color = label_->background_color();
}
void LabelButton::ResetColorsFromNativeTheme() {
@@ -300,26 +331,31 @@ void LabelButton::ResetColorsFromNativeTheme() {
// Certain styles do not change text color when hovered or pressed.
bool constant_text_color = false;
-#if defined(OS_WIN)
- constant_text_color |= (style() == STYLE_NATIVE_TEXTBUTTON &&
- theme == ui::NativeThemeWin::instance());
-#endif
-
// Use hardcoded colors for inverted color scheme support and STYLE_BUTTON.
if (gfx::IsInvertedColorScheme()) {
constant_text_color = true;
colors[STATE_NORMAL] = SK_ColorWHITE;
label_->SetBackgroundColor(SK_ColorBLACK);
+ label_->set_background(Background::CreateSolidBackground(SK_ColorBLACK));
label_->SetAutoColorReadabilityEnabled(true);
- label_->ClearEmbellishing();
+ label_->set_shadows(gfx::ShadowValues());
} else if (style() == STYLE_BUTTON) {
+ // TODO(erg): This is disabled on desktop linux because of the binary asset
+ // confusion. These details should either be pushed into ui::NativeThemeWin
+ // or should be obsoleted by rendering buttons with paint calls instead of
+ // with static assets. http://crbug.com/350498
+#if !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
constant_text_color = true;
colors[STATE_NORMAL] = kStyleButtonTextColor;
label_->SetBackgroundColor(theme->GetSystemColor(
ui::NativeTheme::kColorId_ButtonBackgroundColor));
label_->SetAutoColorReadabilityEnabled(false);
- label_->SetShadowColors(kStyleButtonShadowColor, kStyleButtonShadowColor);
- label_->SetShadowOffset(0, 1);
+ label_->set_shadows(gfx::ShadowValues(1,
+ gfx::ShadowValue(gfx::Point(0, 1), 0, kStyleButtonShadowColor)));
+#endif
+ label_->set_background(NULL);
+ } else {
+ label_->set_background(NULL);
}
if (constant_text_color)
@@ -337,6 +373,27 @@ void LabelButton::UpdateImage() {
image_->SetImage(GetImage(state()));
}
+void LabelButton::UpdateThemedBorder() {
+ // Don't override borders set by others.
+ if (!border_is_themed_border_)
+ return;
+
+ scoped_ptr<LabelButtonBorder> label_button_border = CreateDefaultBorder();
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ views::LinuxUI* linux_ui = views::LinuxUI::instance();
+ if (linux_ui) {
+ SetBorder(linux_ui->CreateNativeBorder(
+ this, label_button_border.Pass()));
+ } else
+#endif
+ {
+ SetBorder(label_button_border.PassAs<Border>());
+ }
+
+ border_is_themed_border_ = true;
+}
+
void LabelButton::StateChanged() {
const gfx::Size previous_image_size(image_->GetPreferredSize());
UpdateImage();
@@ -354,6 +411,9 @@ void LabelButton::ChildPreferredSizeChanged(View* child) {
void LabelButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
ResetColorsFromNativeTheme();
+ UpdateThemedBorder();
+ // Invalidate the layout to pickup the new insets from the border.
+ InvalidateLayout();
}
ui::NativeTheme::Part LabelButton::GetThemePart() const {
@@ -378,13 +438,6 @@ ui::NativeTheme::State LabelButton::GetThemeState(
}
const gfx::Animation* LabelButton::GetThemeAnimation() const {
-#if defined(OS_WIN)
- if (style() == STYLE_NATIVE_TEXTBUTTON &&
- GetNativeTheme() == ui::NativeThemeWin::instance()) {
- return ui::NativeThemeWin::instance()->IsThemingActive() ?
- hover_animation_.get() : NULL;
- }
-#endif
return hover_animation_.get();
}
diff --git a/chromium/ui/views/controls/button/label_button.h b/chromium/ui/views/controls/button/label_button.h
index ad7e226ad5e..80beb3c90d5 100644
--- a/chromium/ui/views/controls/button/label_button.h
+++ b/chromium/ui/views/controls/button/label_button.h
@@ -8,7 +8,6 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/font.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/image_view.h"
@@ -17,6 +16,7 @@
namespace views {
+class LabelButtonBorder;
class Painter;
// LabelButton is an alternative to TextButton, it's not focusable by default.
@@ -28,7 +28,7 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
static const char kViewClassName[];
- LabelButton(ButtonListener* listener, const string16& text);
+ LabelButton(ButtonListener* listener, const base::string16& text);
virtual ~LabelButton();
// Get or set the image shown for the specified button state.
@@ -37,28 +37,37 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
void SetImage(ButtonState for_state, const gfx::ImageSkia& image);
// Get or set the text shown on the button.
- const string16& GetText() const;
- void SetText(const string16& text);
+ const base::string16& GetText() const;
+ virtual void SetText(const base::string16& text);
// Set the text color shown for the specified button state.
void SetTextColor(ButtonState for_state, SkColor color);
+ // Set drop shadows underneath the text.
+ void SetTextShadows(const gfx::ShadowValues& shadows);
+
+ // Sets whether subpixel rendering is used on the label.
+ void SetTextSubpixelRenderingEnabled(bool enabled);
+
// Get or set the text's multi-line property to break on '\n', etc.
bool GetTextMultiLine() const;
void SetTextMultiLine(bool text_multi_line);
- // Get or set the font used by this button.
- const gfx::Font& GetFont() const;
- void SetFont(const gfx::Font& font);
+ // Get or set the font list used by this button.
+ const gfx::FontList& GetFontList() const;
+ void SetFontList(const gfx::FontList& font_list);
// Set the elide behavior of this button.
- void SetElideBehavior(Label::ElideBehavior elide_behavior);
+ void SetElideBehavior(gfx::ElideBehavior elide_behavior);
// Get or set the horizontal alignment used for the button; reversed in RTL.
// The optional image will lead the text, unless the button is right-aligned.
gfx::HorizontalAlignment GetHorizontalAlignment() const;
void SetHorizontalAlignment(gfx::HorizontalAlignment alignment);
+ // Set the directionality mode used for the button text.
+ void SetDirectionalityMode(gfx::DirectionalityMode mode);
+
// Call set_min_size(gfx::Size()) to clear the monotonically increasing size.
void set_min_size(const gfx::Size& min_size) { min_size_ = min_size; }
void set_max_size(const gfx::Size& max_size) { max_size_ = max_size; }
@@ -72,9 +81,11 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
void SetStyle(ButtonStyle style);
void SetFocusPainter(scoped_ptr<Painter> focus_painter);
+ Painter* focus_painter() { return focus_painter_.get(); }
// View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual void SetBorder(scoped_ptr<Border> border) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
@@ -82,10 +93,15 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
ImageView* image() const { return image_; }
Label* label() const { return label_; }
+ // Returns the available area for the label and image. Subclasses can change
+ // these bounds if they need room to do manual painting.
+ virtual gfx::Rect GetChildAreaBounds();
+
// View:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
+ virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
// Fill |params| with information about the button.
virtual void GetExtraParams(ui::NativeTheme::ExtraParams* params) const;
@@ -93,9 +109,17 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
// Resets colors from the NativeTheme, explicitly set colors are unchanged.
virtual void ResetColorsFromNativeTheme();
+ // Creates the default border for this button. This can be overridden by
+ // subclasses or by LinuxUI.
+ virtual scoped_ptr<LabelButtonBorder> CreateDefaultBorder() const;
+
// Updates the image view to contain the appropriate button state image.
void UpdateImage();
+ // Updates the border as per the NativeTheme, unless a different border was
+ // set with SetBorder.
+ void UpdateThemedBorder();
+
// NativeThemeDelegate:
virtual gfx::Rect GetThemePaintRect() const OVERRIDE;
@@ -104,14 +128,13 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Label);
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Image);
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, LabelAndImage);
- FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Font);
+ FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, FontList);
// CustomButton:
virtual void StateChanged() OVERRIDE;
// View:
virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
- virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
// NativeThemeDelegate:
virtual ui::NativeTheme::Part GetThemePart() const OVERRIDE;
@@ -127,6 +150,10 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
ImageView* image_;
Label* label_;
+ // The cached font lists in the normal and bold style.
+ gfx::FontList cached_normal_font_list_;
+ gfx::FontList cached_bold_font_list_;
+
// The images and colors for each button state.
gfx::ImageSkia button_state_images_[STATE_COUNT];
SkColor button_state_colors_[STATE_COUNT];
@@ -135,7 +162,7 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
bool explicitly_set_colors_[STATE_COUNT];
// |min_size_| increases monotonically with the preferred size.
- gfx::Size min_size_;
+ mutable gfx::Size min_size_;
// |max_size_| may be set to clamp the preferred size.
gfx::Size max_size_;
@@ -147,6 +174,9 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
// The button's overall style.
ButtonStyle style_;
+ // True if current border was set by UpdateThemedBorder. Defaults to true.
+ bool border_is_themed_border_;
+
scoped_ptr<Painter> focus_painter_;
DISALLOW_COPY_AND_ASSIGN(LabelButton);
diff --git a/chromium/ui/views/controls/button/label_button_border.cc b/chromium/ui/views/controls/button/label_button_border.cc
index d124764fd76..23e9319ded3 100644
--- a/chromium/ui/views/controls/button/label_button_border.cc
+++ b/chromium/ui/views/controls/button/label_button_border.cc
@@ -31,36 +31,20 @@ const int kButtonInsets = 5;
const int kTextHoveredImages[] = IMAGE_GRID(IDR_TEXTBUTTON_HOVER);
const int kTextPressedImages[] = IMAGE_GRID(IDR_TEXTBUTTON_PRESSED);
-Button::ButtonState GetButtonState(ui::NativeTheme::State state) {
- switch (state) {
- case ui::NativeTheme::kDisabled: return Button::STATE_DISABLED;
- case ui::NativeTheme::kHovered: return Button::STATE_HOVERED;
- case ui::NativeTheme::kNormal: return Button::STATE_NORMAL;
- case ui::NativeTheme::kPressed: return Button::STATE_PRESSED;
- case ui::NativeTheme::kMaxState: NOTREACHED() << "Unknown state: " << state;
- }
- return Button::STATE_NORMAL;
-}
-
-// A helper function to paint the native theme or images as appropriate.
+// A helper function to paint the appropriate broder images.
void PaintHelper(LabelButtonBorder* border,
gfx::Canvas* canvas,
- const ui::NativeTheme* theme,
- ui::NativeTheme::Part part,
ui::NativeTheme::State state,
const gfx::Rect& rect,
const ui::NativeTheme::ExtraParams& extra) {
- if (border->style() == Button::STYLE_NATIVE_TEXTBUTTON) {
- theme->Paint(canvas->sk_canvas(), part, state, rect, extra);
- } else {
- Painter* painter =
- border->GetPainter(extra.button.is_focused, GetButtonState(state));
- // Paint any corresponding unfocused painter if there is no focused painter.
- if (!painter && extra.button.is_focused)
- painter = border->GetPainter(false, GetButtonState(state));
- if (painter)
- Painter::PaintPainterAt(canvas, painter, rect);
- }
+ Painter* painter =
+ border->GetPainter(extra.button.is_focused,
+ Button::GetButtonStateFrom(state));
+ // Paint any corresponding unfocused painter if there is no focused painter.
+ if (!painter && extra.button.is_focused)
+ painter = border->GetPainter(false, Button::GetButtonStateFrom(state));
+ if (painter)
+ Painter::PaintPainterAt(canvas, painter, rect);
}
} // namespace
@@ -105,8 +89,6 @@ LabelButtonBorder::LabelButtonBorder(Button::ButtonStyle style)
Painter::CreateImageGridPainter(kTextHoveredImages));
SetPainter(false, Button::STATE_PRESSED,
Painter::CreateImageGridPainter(kTextPressedImages));
- } else if (style == Button::STYLE_NATIVE_TEXTBUTTON) {
- set_insets(gfx::Insets(5, 12, 5, 12));
}
}
@@ -115,10 +97,8 @@ LabelButtonBorder::~LabelButtonBorder() {}
void LabelButtonBorder::Paint(const View& view, gfx::Canvas* canvas) {
const NativeThemeDelegate* native_theme_delegate =
static_cast<const LabelButton*>(&view);
- ui::NativeTheme::Part part = native_theme_delegate->GetThemePart();
gfx::Rect rect(native_theme_delegate->GetThemePaintRect());
ui::NativeTheme::ExtraParams extra;
- const ui::NativeTheme* theme = view.GetNativeTheme();
const gfx::Animation* animation = native_theme_delegate->GetThemeAnimation();
ui::NativeTheme::State state = native_theme_delegate->GetThemeState(&extra);
@@ -127,7 +107,7 @@ void LabelButtonBorder::Paint(const View& view, gfx::Canvas* canvas) {
const SkRect sk_rect = gfx::RectToSkRect(rect);
canvas->sk_canvas()->saveLayer(&sk_rect, NULL);
state = native_theme_delegate->GetBackgroundThemeState(&extra);
- PaintHelper(this, canvas, theme, part, state, rect, extra);
+ PaintHelper(this, canvas, state, rect, extra);
SkPaint paint;
skia::RefPtr<SkXfermode> sk_lerp_xfer =
@@ -135,18 +115,12 @@ void LabelButtonBorder::Paint(const View& view, gfx::Canvas* canvas) {
paint.setXfermode(sk_lerp_xfer.get());
canvas->sk_canvas()->saveLayer(&sk_rect, &paint);
state = native_theme_delegate->GetForegroundThemeState(&extra);
- PaintHelper(this, canvas, theme, part, state, rect, extra);
+ PaintHelper(this, canvas, state, rect, extra);
canvas->sk_canvas()->restore();
canvas->sk_canvas()->restore();
} else {
- PaintHelper(this, canvas, theme, part, state, rect, extra);
- }
-
- // For inverted color schemes, draw a solid fill with the button color.
- if (gfx::IsInvertedColorScheme()) {
- rect.Inset(insets_);
- canvas->FillRect(rect, extra.button.background_color);
+ PaintHelper(this, canvas, state, rect, extra);
}
}
diff --git a/chromium/ui/views/controls/button/label_button_unittest.cc b/chromium/ui/views/controls/button/label_button_unittest.cc
index fe2d1f670c1..74f77b702e6 100644
--- a/chromium/ui/views/controls/button/label_button_unittest.cc
+++ b/chromium/ui/views/controls/button/label_button_unittest.cc
@@ -2,14 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/controls/button/label_button.h"
+
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/size.h"
-#include "ui/views/controls/button/label_button.h"
+#include "ui/gfx/text_utils.h"
#include "ui/views/test/views_test_base.h"
+using base::ASCIIToUTF16;
+
namespace {
gfx::ImageSkia CreateTestImage(int width, int height) {
@@ -26,7 +30,7 @@ namespace views {
typedef ViewsTestBase LabelButtonTest;
TEST_F(LabelButtonTest, Init) {
- const string16 text(ASCIIToUTF16("abc"));
+ const base::string16 text(ASCIIToUTF16("abc"));
LabelButton button(NULL, text);
EXPECT_TRUE(button.GetImage(Button::STATE_NORMAL).isNull());
@@ -45,19 +49,19 @@ TEST_F(LabelButtonTest, Init) {
}
TEST_F(LabelButtonTest, Label) {
- LabelButton button(NULL, string16());
+ LabelButton button(NULL, base::string16());
EXPECT_TRUE(button.GetText().empty());
- const gfx::Font font;
- const string16 short_text(ASCIIToUTF16("abcdefghijklm"));
- const string16 long_text(ASCIIToUTF16("abcdefghijklmnopqrstuvwxyz"));
- const int short_text_width = gfx::Canvas::GetStringWidth(short_text, font);
- const int long_text_width = gfx::Canvas::GetStringWidth(long_text, font);
+ const gfx::FontList font_list;
+ const base::string16 short_text(ASCIIToUTF16("abcdefghijklm"));
+ const base::string16 long_text(ASCIIToUTF16("abcdefghijklmnopqrstuvwxyz"));
+ const int short_text_width = gfx::GetStringWidth(short_text, font_list);
+ const int long_text_width = gfx::GetStringWidth(long_text, font_list);
// The width increases monotonically with string size (it does not shrink).
EXPECT_LT(button.GetPreferredSize().width(), short_text_width);
button.SetText(short_text);
- EXPECT_GT(button.GetPreferredSize().height(), font.GetHeight());
+ EXPECT_GT(button.GetPreferredSize().height(), font_list.GetHeight());
EXPECT_GT(button.GetPreferredSize().width(), short_text_width);
EXPECT_LT(button.GetPreferredSize().width(), long_text_width);
button.SetText(long_text);
@@ -76,7 +80,7 @@ TEST_F(LabelButtonTest, Label) {
}
TEST_F(LabelButtonTest, Image) {
- LabelButton button(NULL, string16());
+ LabelButton button(NULL, base::string16());
const int small_size = 50, large_size = 100;
const gfx::ImageSkia small_image = CreateTestImage(small_size, small_size);
@@ -108,15 +112,15 @@ TEST_F(LabelButtonTest, Image) {
}
TEST_F(LabelButtonTest, LabelAndImage) {
- LabelButton button(NULL, string16());
+ LabelButton button(NULL, base::string16());
- const gfx::Font font;
- const string16 text(ASCIIToUTF16("abcdefghijklm"));
- const int text_width = gfx::Canvas::GetStringWidth(text, font);
+ const gfx::FontList font_list;
+ const base::string16 text(ASCIIToUTF16("abcdefghijklm"));
+ const int text_width = gfx::GetStringWidth(text, font_list);
const int image_size = 50;
const gfx::ImageSkia image = CreateTestImage(image_size, image_size);
- ASSERT_LT(font.GetHeight(), image_size);
+ ASSERT_LT(font_list.GetHeight(), image_size);
// The width increases monotonically with content size (it does not shrink).
EXPECT_LT(button.GetPreferredSize().width(), text_width);
@@ -124,7 +128,7 @@ TEST_F(LabelButtonTest, LabelAndImage) {
EXPECT_LT(button.GetPreferredSize().height(), image_size);
button.SetText(text);
EXPECT_GT(button.GetPreferredSize().width(), text_width);
- EXPECT_GT(button.GetPreferredSize().height(), font.GetHeight());
+ EXPECT_GT(button.GetPreferredSize().height(), font_list.GetHeight());
EXPECT_LT(button.GetPreferredSize().width(), text_width + image_size);
EXPECT_LT(button.GetPreferredSize().height(), image_size);
button.SetImage(Button::STATE_NORMAL, image);
@@ -146,7 +150,7 @@ TEST_F(LabelButtonTest, LabelAndImage) {
EXPECT_EQ(gfx::ALIGN_RIGHT, button.GetHorizontalAlignment());
EXPECT_LT(button.label_->bounds().right(), button.image_->bounds().x());
- button.SetText(string16());
+ button.SetText(base::string16());
EXPECT_GT(button.GetPreferredSize().width(), text_width + image_size);
EXPECT_GT(button.GetPreferredSize().height(), image_size);
button.SetImage(Button::STATE_NORMAL, gfx::ImageSkia());
@@ -164,24 +168,25 @@ TEST_F(LabelButtonTest, LabelAndImage) {
EXPECT_LT(button.GetPreferredSize().height(), image_size);
}
-TEST_F(LabelButtonTest, Font) {
- const string16 text(ASCIIToUTF16("abc"));
+TEST_F(LabelButtonTest, FontList) {
+ const base::string16 text(ASCIIToUTF16("abc"));
LabelButton button(NULL, text);
- const gfx::Font original_font = button.GetFont();
- const gfx::Font large_font = original_font.DeriveFont(100);
+ const gfx::FontList original_font_list = button.GetFontList();
+ const gfx::FontList large_font_list =
+ original_font_list.DeriveWithSizeDelta(100);
const int original_width = button.GetPreferredSize().width();
const int original_height = button.GetPreferredSize().height();
// The button size increases when the font size is increased.
- button.SetFont(large_font);
+ button.SetFontList(large_font_list);
EXPECT_GT(button.GetPreferredSize().width(), original_width);
EXPECT_GT(button.GetPreferredSize().height(), original_height);
// The button returns to its original size when the minimal size is cleared
// and the original font size is restored.
button.set_min_size(gfx::Size());
- button.SetFont(original_font);
+ button.SetFontList(original_font_list);
EXPECT_EQ(original_width, button.GetPreferredSize().width());
EXPECT_EQ(original_height, button.GetPreferredSize().height());
}
diff --git a/chromium/ui/views/controls/button/menu_button.cc b/chromium/ui/views/controls/button/menu_button.cc
index 728c0371f1c..29271cea51f 100644
--- a/chromium/ui/views/controls/button/menu_button.cc
+++ b/chromium/ui/views/controls/button/menu_button.cc
@@ -7,7 +7,7 @@
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
@@ -16,6 +16,7 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/screen.h"
+#include "ui/gfx/text_constants.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/menu_button_listener.h"
#include "ui/views/mouse_constants.h"
@@ -43,10 +44,10 @@ const int MenuButton::kMenuMarkerPaddingRight = -1;
////////////////////////////////////////////////////////////////////////////////
MenuButton::MenuButton(ButtonListener* listener,
- const string16& text,
+ const base::string16& text,
MenuButtonListener* menu_button_listener,
bool show_menu_marker)
- : TextButton(listener, text),
+ : LabelButton(listener, text),
menu_visible_(false),
menu_offset_(kDefaultMenuOffsetX, kDefaultMenuOffsetY),
listener_(menu_button_listener),
@@ -54,7 +55,7 @@ MenuButton::MenuButton(ButtonListener* listener,
menu_marker_(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_MENU_DROPARROW).ToImageSkia()),
destroyed_flag_(NULL) {
- set_alignment(TextButton::ALIGN_LEFT);
+ SetHorizontalAlignment(gfx::ALIGN_LEFT);
}
MenuButton::~MenuButton() {
@@ -133,8 +134,8 @@ bool MenuButton::Activate() {
return true;
}
-void MenuButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
- TextButton::PaintButton(canvas, mode);
+void MenuButton::OnPaint(gfx::Canvas* canvas) {
+ LabelButton::OnPaint(canvas);
if (show_menu_marker_)
PaintMenuMarker(canvas);
@@ -146,8 +147,8 @@ void MenuButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
//
////////////////////////////////////////////////////////////////////////////////
-gfx::Size MenuButton::GetPreferredSize() {
- gfx::Size prefsize = TextButton::GetPreferredSize();
+gfx::Size MenuButton::GetPreferredSize() const {
+ gfx::Size prefsize = LabelButton::GetPreferredSize();
if (show_menu_marker_) {
prefsize.Enlarge(menu_marker_->width() + kMenuMarkerPaddingLeft +
kMenuMarkerPaddingRight,
@@ -186,7 +187,7 @@ void MenuButton::OnMouseReleased(const ui::MouseEvent& event) {
HitTestPoint(event.location())) {
Activate();
} else {
- TextButton::OnMouseReleased(event);
+ LabelButton::OnMouseReleased(event);
}
}
@@ -202,12 +203,14 @@ void MenuButton::OnMouseExited(const ui::MouseEvent& event) {
}
void MenuButton::OnGestureEvent(ui::GestureEvent* event) {
- if (state() != STATE_DISABLED && event->type() == ui::ET_GESTURE_TAP) {
- if (Activate())
- event->StopPropagation();
+ if (state() != STATE_DISABLED && event->type() == ui::ET_GESTURE_TAP &&
+ !Activate()) {
+ // When |Activate()| returns |false|, it means that a menu is shown and
+ // has handled the gesture event. So, there is no need to further process
+ // the gesture event here.
return;
}
- TextButton::OnGestureEvent(event);
+ LabelButton::OnGestureEvent(event);
}
bool MenuButton::OnKeyPressed(const ui::KeyEvent& event) {
@@ -220,16 +223,12 @@ bool MenuButton::OnKeyPressed(const ui::KeyEvent& event) {
case ui::VKEY_UP:
case ui::VKEY_DOWN: {
// WARNING: we may have been deleted by the time Activate returns.
- bool ret = Activate();
-#if defined(USE_AURA)
- // This is to prevent the keyboard event from being dispatched twice.
- // The Activate function returns false in most cases. In AURA if the
- // keyboard event is not handled, we pass it to the default handler
- // which dispatches the event back to us causing the menu to get
- // displayed again.
- ret = true;
-#endif
- return ret;
+ Activate();
+ // This is to prevent the keyboard event from being dispatched twice. If
+ // the keyboard event is not handled, we pass it to the default handler
+ // which dispatches the event back to us causing the menu to get displayed
+ // again. Return true to prevent this.
+ return true;
}
default:
break;
@@ -244,11 +243,11 @@ bool MenuButton::OnKeyReleased(const ui::KeyEvent& event) {
return false;
}
-void MenuButton::GetAccessibleState(ui::AccessibleViewState* state) {
+void MenuButton::GetAccessibleState(ui::AXViewState* state) {
CustomButton::GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_BUTTONMENU;
+ state->role = ui::AX_ROLE_POP_UP_BUTTON;
state->default_action = l10n_util::GetStringUTF16(IDS_APP_ACCACTION_PRESS);
- state->state = ui::AccessibilityTypes::STATE_HASPOPUP;
+ state->AddStateFlag(ui::AX_STATE_HASPOPUP);
}
void MenuButton::PaintMenuMarker(gfx::Canvas* canvas) {
@@ -267,6 +266,17 @@ void MenuButton::PaintMenuMarker(gfx::Canvas* canvas) {
canvas->DrawImageInt(*menu_marker_, arrow_bounds.x(), arrow_bounds.y());
}
+gfx::Rect MenuButton::GetChildAreaBounds() {
+ gfx::Size s = size();
+
+ if (show_menu_marker_) {
+ s.set_width(s.width() - menu_marker_->width() - kMenuMarkerPaddingLeft -
+ kMenuMarkerPaddingRight);
+ }
+
+ return gfx::Rect(s);
+}
+
int MenuButton::GetMaximumScreenXCoordinate() {
if (!GetWidget()) {
NOTREACHED();
diff --git a/chromium/ui/views/controls/button/menu_button.h b/chromium/ui/views/controls/button/menu_button.h
index 2262dab4637..257d2f62ea9 100644
--- a/chromium/ui/views/controls/button/menu_button.h
+++ b/chromium/ui/views/controls/button/menu_button.h
@@ -9,9 +9,8 @@
#include "base/strings/string16.h"
#include "base/time/time.h"
-#include "ui/gfx/font.h"
#include "ui/views/background.h"
-#include "ui/views/controls/button/text_button.h"
+#include "ui/views/controls/button/label_button.h"
namespace views {
@@ -24,7 +23,7 @@ class MenuButtonListener;
// A button that shows a menu when the left mouse button is pushed
//
////////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT MenuButton : public TextButton {
+class VIEWS_EXPORT MenuButton : public LabelButton {
public:
static const char kViewClassName[];
@@ -34,7 +33,7 @@ class VIEWS_EXPORT MenuButton : public TextButton {
// Create a Button.
MenuButton(ButtonListener* listener,
- const string16& text,
+ const base::string16& text,
MenuButtonListener* menu_button_listener,
bool show_menu_marker);
virtual ~MenuButton();
@@ -51,24 +50,25 @@ class VIEWS_EXPORT MenuButton : public TextButton {
// Activate the button (called when the button is pressed).
virtual bool Activate();
- // Overridden from TextButton for the potential use of a drop marker.
- virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) OVERRIDE;
-
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// Paint the menu marker image.
void PaintMenuMarker(gfx::Canvas* canvas);
+ // Overridden from LabelButton:
+ virtual gfx::Rect GetChildAreaBounds() OVERRIDE;
+
// True if the menu is currently visible.
bool menu_visible_;
diff --git a/chromium/ui/views/controls/button/menu_button_unittest.cc b/chromium/ui/views/controls/button/menu_button_unittest.cc
new file mode 100644
index 00000000000..6a18b21b104
--- /dev/null
+++ b/chromium/ui/views/controls/button/menu_button_unittest.cc
@@ -0,0 +1,199 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/button/menu_button.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
+#include "ui/views/controls/button/menu_button_listener.h"
+#include "ui/views/test/views_test_base.h"
+
+using base::ASCIIToUTF16;
+
+namespace views {
+
+class MenuButtonTest : public ViewsTestBase {
+ public:
+ MenuButtonTest() : widget_(NULL), button_(NULL) {}
+ virtual ~MenuButtonTest() {}
+
+ virtual void TearDown() OVERRIDE {
+ if (widget_ && !widget_->IsClosed())
+ widget_->Close();
+
+ ViewsTestBase::TearDown();
+ }
+
+ Widget* widget() { return widget_; }
+ MenuButton* button() { return button_; }
+
+ protected:
+ // Creates a MenuButton with a ButtonListener. In this case, the MenuButton
+ // acts like a regular button.
+ void CreateMenuButtonWithButtonListener(ButtonListener* button_listener) {
+ CreateWidget();
+
+ const base::string16 label(ASCIIToUTF16("button"));
+ button_ = new MenuButton(button_listener, label, NULL, false);
+ button_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
+ widget_->SetContentsView(button_);
+
+ widget_->Show();
+ }
+
+ // Creates a MenuButton with a MenuButtonListener. In this case, when the
+ // MenuButton is pushed, it notifies the MenuButtonListener to open a
+ // drop-down menu.
+ void CreateMenuButtonWithMenuButtonListener(
+ MenuButtonListener* menu_button_listener) {
+ CreateWidget();
+
+ const base::string16 label(ASCIIToUTF16("button"));
+ button_ = new MenuButton(NULL, label, menu_button_listener, false);
+ button_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
+ widget_->SetContentsView(button_);
+
+ widget_->Show();
+ }
+
+ private:
+ void CreateWidget() {
+ DCHECK(!widget_);
+
+ widget_ = new Widget;
+ Widget::InitParams params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ widget_->Init(params);
+ }
+
+ Widget* widget_;
+ MenuButton* button_;
+};
+
+class TestButtonListener : public ButtonListener {
+ public:
+ TestButtonListener()
+ : last_sender_(NULL),
+ last_sender_state_(Button::STATE_NORMAL),
+ last_event_type_(ui::ET_UNKNOWN) {}
+ virtual ~TestButtonListener() {}
+
+ virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE {
+ last_sender_ = sender;
+ CustomButton* custom_button = CustomButton::AsCustomButton(sender);
+ DCHECK(custom_button);
+ last_sender_state_ = custom_button->state();
+ last_event_type_ = event.type();
+ }
+
+ Button* last_sender() { return last_sender_; }
+ Button::ButtonState last_sender_state() { return last_sender_state_; }
+ ui::EventType last_event_type() { return last_event_type_; }
+
+ private:
+ Button* last_sender_;
+ Button::ButtonState last_sender_state_;
+ ui::EventType last_event_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestButtonListener);
+};
+
+class TestMenuButtonListener : public MenuButtonListener {
+ public:
+ TestMenuButtonListener() {}
+ virtual ~TestMenuButtonListener() {}
+
+ virtual void OnMenuButtonClicked(View* source,
+ const gfx::Point& /*point*/) OVERRIDE {
+ last_source_ = source;
+ CustomButton* custom_button = CustomButton::AsCustomButton(source);
+ DCHECK(custom_button);
+ last_source_state_ = custom_button->state();
+ }
+
+ View* last_source() { return last_source_; }
+ Button::ButtonState last_source_state() { return last_source_state_; }
+
+ private:
+ View* last_source_;
+ Button::ButtonState last_source_state_;
+};
+
+// Tests if the listener is notified correctly, when a mouse click happens on a
+// MenuButton that has a regular ButtonListener.
+TEST_F(MenuButtonTest, ActivateNonDropDownOnMouseClick) {
+ scoped_ptr<TestButtonListener> button_listener(new TestButtonListener);
+ CreateMenuButtonWithButtonListener(button_listener.get());
+
+ aura::test::EventGenerator generator(
+ widget()->GetNativeView()->GetRootWindow());
+
+ generator.set_current_location(gfx::Point(10, 10));
+ generator.ClickLeftButton();
+
+ // Check that MenuButton has notified the listener on mouse-released event,
+ // while it was in hovered state.
+ EXPECT_EQ(button(), button_listener->last_sender());
+ EXPECT_EQ(ui::ET_MOUSE_RELEASED, button_listener->last_event_type());
+ EXPECT_EQ(Button::STATE_HOVERED, button_listener->last_sender_state());
+}
+
+// Tests if the listener is notified correctly when a gesture tap happens on a
+// MenuButton that has a regular ButtonListener.
+TEST_F(MenuButtonTest, ActivateNonDropDownOnGestureTap) {
+ scoped_ptr<TestButtonListener> button_listener(new TestButtonListener);
+ CreateMenuButtonWithButtonListener(button_listener.get());
+
+ aura::test::EventGenerator generator(
+ widget()->GetNativeView()->GetRootWindow());
+
+ generator.GestureTapAt(gfx::Point(10, 10));
+
+ // Check that MenuButton has notified the listener on gesture tap event, while
+ // it was in hovered state.
+ EXPECT_EQ(button(), button_listener->last_sender());
+ EXPECT_EQ(ui::ET_GESTURE_TAP, button_listener->last_event_type());
+ EXPECT_EQ(Button::STATE_HOVERED, button_listener->last_sender_state());
+}
+
+// Tests if the listener is notified correctly when a mouse click happens on a
+// MenuButton that has a MenuButtonListener.
+TEST_F(MenuButtonTest, ActivateDropDownOnMouseClick) {
+ scoped_ptr<TestMenuButtonListener> menu_button_listener(
+ new TestMenuButtonListener);
+ CreateMenuButtonWithMenuButtonListener(menu_button_listener.get());
+
+ aura::test::EventGenerator generator(
+ widget()->GetNativeView()->GetRootWindow());
+
+ generator.set_current_location(gfx::Point(10, 10));
+ generator.ClickLeftButton();
+
+ // Check that MenuButton has notified the listener, while it was in pressed
+ // state.
+ EXPECT_EQ(button(), menu_button_listener->last_source());
+ EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener->last_source_state());
+}
+
+// Tests if the listener is notified correctly when a gesture tap happens on a
+// MenuButton that has a MenuButtonListener.
+TEST_F(MenuButtonTest, ActivateDropDownOnGestureTap) {
+ scoped_ptr<TestMenuButtonListener> menu_button_listener(
+ new TestMenuButtonListener);
+ CreateMenuButtonWithMenuButtonListener(menu_button_listener.get());
+
+ aura::test::EventGenerator generator(
+ widget()->GetNativeView()->GetRootWindow());
+
+ generator.GestureTapAt(gfx::Point(10, 10));
+
+ // Check that MenuButton has notified the listener, while it was in pressed
+ // state.
+ EXPECT_EQ(button(), menu_button_listener->last_source());
+ EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener->last_source_state());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/radio_button.cc b/chromium/ui/views/controls/button/radio_button.cc
index 224e9893873..a015d5e1da8 100644
--- a/chromium/ui/views/controls/button/radio_button.cc
+++ b/chromium/ui/views/controls/button/radio_button.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/widget/widget.h"
@@ -15,7 +15,7 @@ namespace views {
// static
const char RadioButton::kViewClassName[] = "RadioButton";
-RadioButton::RadioButton(const string16& label, int group_id)
+RadioButton::RadioButton(const base::string16& label, int group_id)
: Checkbox(label) {
SetGroup(group_id);
@@ -94,9 +94,9 @@ const char* RadioButton::GetClassName() const {
return kViewClassName;
}
-void RadioButton::GetAccessibleState(ui::AccessibleViewState* state) {
+void RadioButton::GetAccessibleState(ui::AXViewState* state) {
Checkbox::GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_RADIOBUTTON;
+ state->role = ui::AX_ROLE_RADIO_BUTTON;
}
View* RadioButton::GetSelectedViewForGroup(int group) {
@@ -123,7 +123,7 @@ bool RadioButton::IsGroupFocusTraversable() const {
void RadioButton::OnFocus() {
Checkbox::OnFocus();
SetChecked(true);
- ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 0);
+ ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 0, 0);
LabelButton::NotifyClick(event);
}
diff --git a/chromium/ui/views/controls/button/radio_button.h b/chromium/ui/views/controls/button/radio_button.h
index a7afff4ed41..edbb2c694cd 100644
--- a/chromium/ui/views/controls/button/radio_button.h
+++ b/chromium/ui/views/controls/button/radio_button.h
@@ -17,12 +17,12 @@ class VIEWS_EXPORT RadioButton : public Checkbox {
// The button's class name.
static const char kViewClassName[];
- RadioButton(const string16& label, int group_id);
+ RadioButton(const base::string16& label, int group_id);
virtual ~RadioButton();
// Overridden from View:
virtual const char* GetClassName() const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual View* GetSelectedViewForGroup(int group) OVERRIDE;
virtual bool IsGroupFocusTraversable() const OVERRIDE;
virtual void OnFocus() OVERRIDE;
@@ -30,7 +30,7 @@ class VIEWS_EXPORT RadioButton : public Checkbox {
// Overridden from Button:
virtual void NotifyClick(const ui::Event& event) OVERRIDE;
- // Overridden from TextButtonBase:
+ // Overridden from LabelButton:
virtual ui::NativeTheme::Part GetThemePart() const OVERRIDE;
// Overridden from Checkbox:
diff --git a/chromium/ui/views/controls/button/text_button.cc b/chromium/ui/views/controls/button/text_button.cc
index e829405b9f4..bf12f8e086d 100644
--- a/chromium/ui/views/controls/button/text_button.cc
+++ b/chromium/ui/views/controls/button/text_button.cc
@@ -88,14 +88,6 @@ void TextButtonBorder::SetInsets(const gfx::Insets& insets) {
insets_ = insets;
}
-TextButtonBorder* TextButtonBorder::AsTextButtonBorder() {
- return this;
-}
-
-const TextButtonBorder* TextButtonBorder::AsTextButtonBorder() const {
- return this;
-}
-
// TextButtonDefaultBorder ----------------------------------------------------
@@ -199,15 +191,10 @@ void TextButtonNativeThemeBorder::Paint(const View& view, gfx::Canvas* canvas) {
// TextButtonBase -------------------------------------------------------------
-TextButtonBase::TextButtonBase(ButtonListener* listener, const string16& text)
+TextButtonBase::TextButtonBase(ButtonListener* listener,
+ const base::string16& text)
: CustomButton(listener),
alignment_(ALIGN_LEFT),
- font_(ResourceBundle::GetSharedInstance().GetFont(
- ResourceBundle::BaseFont)),
- has_text_shadow_(false),
- active_text_shadow_color_(0),
- inactive_text_shadow_color_(0),
- text_shadow_offset_(gfx::Point(1, 1)),
min_width_(0),
min_height_(0),
max_width_(0),
@@ -220,8 +207,6 @@ TextButtonBase::TextButtonBase(ButtonListener* listener, const string16& text)
use_hover_color_from_theme_(true),
focus_painter_(Painter::CreateDashedFocusPainter()) {
SetText(text);
- // OnNativeThemeChanged sets the color member variables.
- TextButtonBase::OnNativeThemeChanged(GetNativeTheme());
SetAnimationDuration(kHoverAnimationDurationMs);
}
@@ -239,7 +224,7 @@ void TextButtonBase::SetIsDefault(bool is_default) {
SchedulePaint();
}
-void TextButtonBase::SetText(const string16& text) {
+void TextButtonBase::SetText(const base::string16& text) {
if (text == text_)
return;
text_ = text;
@@ -247,8 +232,8 @@ void TextButtonBase::SetText(const string16& text) {
UpdateTextSize();
}
-void TextButtonBase::SetFont(const gfx::Font& font) {
- font_ = font;
+void TextButtonBase::SetFontList(const gfx::FontList& font_list) {
+ font_list_ = font_list;
UpdateTextSize();
}
@@ -274,21 +259,6 @@ void TextButtonBase::SetHoverColor(SkColor color) {
use_hover_color_from_theme_ = false;
}
-void TextButtonBase::SetTextShadowColors(SkColor active_color,
- SkColor inactive_color) {
- active_text_shadow_color_ = active_color;
- inactive_text_shadow_color_ = inactive_color;
- has_text_shadow_ = true;
-}
-
-void TextButtonBase::SetTextShadowOffset(int x, int y) {
- text_shadow_offset_.SetPoint(x, y);
-}
-
-void TextButtonBase::ClearEmbellishing() {
- has_text_shadow_ = false;
-}
-
void TextButtonBase::ClearMaxTextSize() {
max_text_size_ = text_size_;
}
@@ -306,7 +276,7 @@ void TextButtonBase::SetMultiLine(bool multi_line) {
}
}
-gfx::Size TextButtonBase::GetPreferredSize() {
+gfx::Size TextButtonBase::GetPreferredSize() const {
gfx::Insets insets = GetInsets();
// Use the max size to set the button boundaries.
@@ -326,7 +296,7 @@ gfx::Size TextButtonBase::GetPreferredSize() {
return prefsize;
}
-int TextButtonBase::GetHeightForWidth(int w) {
+int TextButtonBase::GetHeightForWidth(int w) const {
if (!multi_line_)
return View::GetHeightForWidth(w);
@@ -377,17 +347,51 @@ void TextButtonBase::UpdateTextSize() {
}
}
-void TextButtonBase::CalculateTextSize(gfx::Size* text_size, int max_width) {
- int h = font_.GetHeight();
+void TextButtonBase::CalculateTextSize(gfx::Size* text_size,
+ int max_width) const {
+ int h = font_list_.GetHeight();
int w = multi_line_ ? max_width : 0;
int flags = ComputeCanvasStringFlags();
if (!multi_line_)
flags |= gfx::Canvas::NO_ELLIPSIS;
- gfx::Canvas::SizeStringInt(text_, font_, &w, &h, 0, flags);
+ gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, 0, flags);
text_size->SetSize(w, h);
}
+void TextButtonBase::OnPaintText(gfx::Canvas* canvas, PaintButtonMode mode) {
+ gfx::Rect text_bounds(GetTextBounds());
+ if (text_bounds.width() > 0) {
+ // Because the text button can (at times) draw multiple elements on the
+ // canvas, we can not mirror the button by simply flipping the canvas as
+ // doing this will mirror the text itself. Flipping the canvas will also
+ // make the icons look wrong because icons are almost always represented as
+ // direction-insensitive images and such images should never be flipped
+ // horizontally.
+ //
+ // Due to the above, we must perform the flipping manually for RTL UIs.
+ text_bounds.set_x(GetMirroredXForRect(text_bounds));
+
+ SkColor text_color = (show_multiple_icon_states_ &&
+ (state() == STATE_HOVERED || state() == STATE_PRESSED)) ?
+ color_hover_ : color_;
+
+ int draw_string_flags = gfx::Canvas::DefaultCanvasTextAlignment() |
+ ComputeCanvasStringFlags();
+
+ if (mode == PB_FOR_DRAG) {
+ // Disable sub-pixel rendering as background is transparent.
+ draw_string_flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
+ canvas->DrawStringRectWithHalo(text_, font_list_,
+ SK_ColorBLACK, SK_ColorWHITE,
+ text_bounds, draw_string_flags);
+ } else {
+ canvas->DrawStringRectWithFlags(text_, font_list_, text_color,
+ text_bounds, draw_string_flags);
+ }
+ }
+}
+
int TextButtonBase::ComputeCanvasStringFlags() const {
if (!multi_line_)
return 0;
@@ -475,59 +479,10 @@ void TextButtonBase::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
}
- gfx::Rect text_bounds(GetTextBounds());
- if (text_bounds.width() > 0) {
- // Because the text button can (at times) draw multiple elements on the
- // canvas, we can not mirror the button by simply flipping the canvas as
- // doing this will mirror the text itself. Flipping the canvas will also
- // make the icons look wrong because icons are almost always represented as
- // direction-insensitive images and such images should never be flipped
- // horizontally.
- //
- // Due to the above, we must perform the flipping manually for RTL UIs.
- text_bounds.set_x(GetMirroredXForRect(text_bounds));
-
- SkColor text_color = (show_multiple_icon_states_ &&
- (state() == STATE_HOVERED || state() == STATE_PRESSED)) ?
- color_hover_ : color_;
-
- int draw_string_flags = gfx::Canvas::DefaultCanvasTextAlignment() |
- ComputeCanvasStringFlags();
-
- if (mode == PB_FOR_DRAG) {
- // Disable sub-pixel rendering as background is transparent.
- draw_string_flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
-
-#if defined(OS_WIN)
- // TODO(erg): Either port DrawStringWithHalo to linux or find an
- // alternative here.
- canvas->DrawStringWithHalo(text_, font_, SK_ColorBLACK, SK_ColorWHITE,
- text_bounds.x(), text_bounds.y(), text_bounds.width(),
- text_bounds.height(), draw_string_flags);
-#else
- canvas->DrawStringInt(text_,
- font_,
- text_color,
- text_bounds.x(),
- text_bounds.y(),
- text_bounds.width(),
- text_bounds.height(),
- draw_string_flags);
-#endif
- } else {
- gfx::ShadowValues shadows;
- if (has_text_shadow_) {
- SkColor color = GetWidget()->IsActive() ? active_text_shadow_color_ :
- inactive_text_shadow_color_;
- shadows.push_back(gfx::ShadowValue(text_shadow_offset_, 0, color));
- }
- canvas->DrawStringWithShadows(text_, font_, text_color, text_bounds,
- 0, draw_string_flags, shadows);
- }
- }
+ OnPaintText(canvas, mode);
}
-gfx::Size TextButtonBase::GetMinimumSize() {
+gfx::Size TextButtonBase::GetMinimumSize() const {
return max_text_size_;
}
@@ -609,14 +564,15 @@ ui::NativeTheme::State TextButtonBase::GetForegroundThemeState(
// TextButton -----------------------------------------------------------------
-TextButton::TextButton(ButtonListener* listener, const string16& text)
+TextButton::TextButton(ButtonListener* listener, const base::string16& text)
: TextButtonBase(listener, text),
icon_placement_(ICON_ON_LEFT),
has_hover_icon_(false),
has_pushed_icon_(false),
icon_text_spacing_(kDefaultIconTextSpacing),
- ignore_minimum_size_(true) {
- set_border(new TextButtonDefaultBorder);
+ ignore_minimum_size_(true),
+ full_justification_(false) {
+ SetBorder(scoped_ptr<Border>(new TextButtonDefaultBorder));
SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(
gfx::Insets(kFocusRectInset, kFocusRectInset,
kFocusRectInset, kFocusRectInset)));
@@ -642,7 +598,7 @@ void TextButton::SetPushedIcon(const gfx::ImageSkia& icon) {
SchedulePaint();
}
-gfx::Size TextButton::GetPreferredSize() {
+gfx::Size TextButton::GetPreferredSize() const {
gfx::Size prefsize(TextButtonBase::GetPreferredSize());
prefsize.Enlarge(icon_.width(), 0);
prefsize.set_height(std::max(prefsize.height(), icon_.height()));
@@ -657,8 +613,8 @@ gfx::Size TextButton::GetPreferredSize() {
#if defined(OS_WIN)
// Clamp the size returned to at least the minimum size.
if (!ignore_minimum_size_) {
- gfx::PlatformFontWin* platform_font =
- static_cast<gfx::PlatformFontWin*>(font_.platform_font());
+ gfx::PlatformFontWin* platform_font = static_cast<gfx::PlatformFontWin*>(
+ font_list_.GetPrimaryFont().platform_font());
prefsize.set_width(std::max(
prefsize.width(),
platform_font->horizontal_dlus_to_pixels(kMinWidthDLUs)));
@@ -675,22 +631,37 @@ gfx::Size TextButton::GetPreferredSize() {
}
void TextButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
+ if (full_justification_ && icon_placement_ == ICON_ON_LEFT)
+ set_alignment(ALIGN_RIGHT);
+
TextButtonBase::PaintButton(canvas, mode);
+ OnPaintIcon(canvas, mode);
+}
+void TextButton::OnPaintIcon(gfx::Canvas* canvas, PaintButtonMode mode) {
const gfx::ImageSkia& icon = GetImageToPaint();
if (icon.width() > 0) {
gfx::Rect text_bounds = GetTextBounds();
- int icon_x;
+ int icon_x = 0;
int spacing = text_.empty() ? 0 : icon_text_spacing_;
gfx::Insets insets = GetInsets();
- if (icon_placement_ == ICON_ON_LEFT) {
- icon_x = text_bounds.x() - icon.width() - spacing;
- } else if (icon_placement_ == ICON_ON_RIGHT) {
- icon_x = text_bounds.right() + spacing;
- } else { // ICON_CENTERED
- DCHECK(text_.empty());
- icon_x = (width() - insets.width() - icon.width()) / 2 + insets.left();
+ switch (icon_placement_) {
+ case ICON_ON_LEFT:
+ icon_x = full_justification_ ? insets.left()
+ : text_bounds.x() - icon.width() - spacing;
+ break;
+ case ICON_ON_RIGHT:
+ icon_x = full_justification_ ? width() - insets.right() - icon.width()
+ : text_bounds.right() + spacing;
+ break;
+ case ICON_CENTERED:
+ DCHECK(text_.empty());
+ icon_x = (width() - insets.width() - icon.width()) / 2 + insets.left();
+ break;
+ default:
+ NOTREACHED();
+ break;
}
int available_height = height() - insets.height();
@@ -707,6 +678,10 @@ void TextButton::set_ignore_minimum_size(bool ignore_minimum_size) {
ignore_minimum_size_ = ignore_minimum_size;
}
+void TextButton::set_full_justification(bool full_justification) {
+ full_justification_ = full_justification;
+}
+
const char* TextButton::GetClassName() const {
return kViewClassName;
}
diff --git a/chromium/ui/views/controls/button/text_button.h b/chromium/ui/views/controls/button/text_button.h
index 4dc61577803..49c4f3f8c17 100644
--- a/chromium/ui/views/controls/button/text_button.h
+++ b/chromium/ui/views/controls/button/text_button.h
@@ -11,7 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/custom_button.h"
@@ -35,10 +35,6 @@ class VIEWS_EXPORT TextButtonBorder : public Border {
virtual gfx::Size GetMinimumSize() const OVERRIDE;
private:
- // Border:
- virtual TextButtonBorder* AsTextButtonBorder() OVERRIDE;
- virtual const TextButtonBorder* AsTextButtonBorder() const OVERRIDE;
-
gfx::Insets insets_;
DISALLOW_COPY_AND_ASSIGN(TextButtonBorder);
@@ -112,8 +108,8 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
// Call SetText once per string in your set of possible values at button
// creation time, so that it can contain the largest of them and avoid
// resizing the button when the text changes.
- virtual void SetText(const string16& text);
- const string16& text() const { return text_; }
+ virtual void SetText(const base::string16& text);
+ const base::string16& text() const { return text_; }
enum TextAlignment {
ALIGN_LEFT,
@@ -143,24 +139,14 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
void set_min_width(int min_width) { min_width_ = min_width; }
void set_min_height(int min_height) { min_height_ = min_height; }
void set_max_width(int max_width) { max_width_ = max_width; }
- void SetFont(const gfx::Font& font);
- // Return the font used by this button.
- gfx::Font font() const { return font_; }
+ const gfx::FontList& font_list() const { return font_list_; }
+ void SetFontList(const gfx::FontList& font_list);
void SetEnabledColor(SkColor color);
void SetDisabledColor(SkColor color);
void SetHighlightColor(SkColor color);
void SetHoverColor(SkColor color);
- // Enables a drop shadow underneath the text.
- void SetTextShadowColors(SkColor active_color, SkColor inactive_color);
-
- // Sets the drop shadow's offset from the text.
- void SetTextShadowOffset(int x, int y);
-
- // Disables shadows.
- void ClearEmbellishing();
-
// Sets whether or not to show the hot and pushed states for the button icon
// (if present) in addition to the normal state. Defaults to true.
bool show_multiple_icon_states() const { return show_multiple_icon_states_; }
@@ -175,9 +161,9 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode);
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
- virtual int GetHeightForWidth(int w) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int w) const OVERRIDE;
virtual void OnEnabledChanged() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
@@ -185,18 +171,23 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
protected:
- TextButtonBase(ButtonListener* listener, const string16& text);
+ TextButtonBase(ButtonListener* listener, const base::string16& text);
// Called when enabled or disabled state changes, or the colors for those
// states change.
virtual void UpdateColor();
// Updates text_size_ and max_text_size_ from the current text/font. This is
- // invoked when the font or text changes.
+ // invoked when the font list or text changes.
void UpdateTextSize();
// Calculate the size of the text size without setting any of the members.
- void CalculateTextSize(gfx::Size* text_size, int max_width);
+ void CalculateTextSize(gfx::Size* text_size, int max_width) const;
+
+ // Paint the button's text into the specified canvas. If |mode| is
+ // |PB_FOR_DRAG|, the function paints a drag image representation. Derived
+ // can override this function to change only the text rendering.
+ virtual void OnPaintText(gfx::Canvas* canvas, PaintButtonMode mode);
void set_color_enabled(SkColor color) { color_enabled_ = color; }
void set_color_disabled(SkColor color) { color_disabled_ = color; }
@@ -239,10 +230,10 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
gfx::Rect GetContentBounds(int extra_width) const;
// The text string that is displayed in the button.
- string16 text_;
+ base::string16 text_;
// The size of the text string.
- gfx::Size text_size_;
+ mutable gfx::Size text_size_;
// Track the size of the largest text string seen so far, so that
// changing text_ will not resize the button boundary.
@@ -251,16 +242,8 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
// The alignment of the text string within the button.
TextAlignment alignment_;
- // The font used to paint the text.
- gfx::Font font_;
-
- // Flag indicating if a shadow should be drawn behind the text.
- bool has_text_shadow_;
- // Optional shadow text colors for active and inactive widget states.
- SkColor active_text_shadow_color_;
- SkColor inactive_text_shadow_color_;
- // Space between the text and its shadow. Defaults to (1,1).
- gfx::Point text_shadow_offset_;
+ // The font list used to paint the text.
+ gfx::FontList font_list_;
// The dimensions of the button will be at least these values.
int min_width_;
@@ -310,7 +293,7 @@ class VIEWS_EXPORT TextButton : public TextButtonBase {
// The button's class name.
static const char kViewClassName[];
- TextButton(ButtonListener* listener, const string16& text);
+ TextButton(ButtonListener* listener, const base::string16& text);
virtual ~TextButton();
void set_icon_text_spacing(int icon_text_spacing) {
@@ -340,14 +323,21 @@ class VIEWS_EXPORT TextButton : public TextButtonBase {
void set_ignore_minimum_size(bool ignore_minimum_size);
+ void set_full_justification(bool full_justification);
+
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
// Overridden from TextButtonBase:
virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) OVERRIDE;
protected:
+ // Paint the button's icon into the specified canvas. If |mode| is
+ // |PB_FOR_DRAG|, the function paints a drag image representation. Derived
+ // can override this function to change only the icon rendering.
+ virtual void OnPaintIcon(gfx::Canvas* canvas, PaintButtonMode mode);
+
gfx::ImageSkia icon() const { return icon_; }
virtual const gfx::ImageSkia& GetImageToPaint() const;
@@ -382,6 +372,10 @@ class VIEWS_EXPORT TextButton : public TextButtonBase {
// is true. Set to false to prevent narrower buttons.
bool ignore_minimum_size_;
+ // True if the icon and the text are aligned along both the left and right
+ // margins of the button.
+ bool full_justification_;
+
DISALLOW_COPY_AND_ASSIGN(TextButton);
};
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc
index 7feb5ffd0a7..b2a456d4906 100644
--- a/chromium/ui/views/controls/combobox/combobox.cc
+++ b/chromium/ui/views/controls/combobox/combobox.cc
@@ -4,10 +4,12 @@
#include "ui/views/controls/combobox/combobox.h"
+#include "base/bind.h"
#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
@@ -16,6 +18,8 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/scoped_canvas.h"
+#include "ui/gfx/text_utils.h"
+#include "ui/native_theme/common_theme.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/color_constants.h"
@@ -23,6 +27,7 @@
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/controls/focusable_border.h"
+#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/menu/menu_runner_handler.h"
#include "ui/views/controls/menu/submenu_view.h"
@@ -53,8 +58,6 @@ const int kDisclosureArrowButtonRightPadding = 12;
// Define the id of the first item in the menu (since it needs to be > 0)
const int kFirstMenuItemId = 1000;
-const SkColor kInvalidTextColor = SK_ColorWHITE;
-
// Used to indicate that no item is currently selected by the user.
const int kNoSelection = -1;
@@ -81,24 +84,6 @@ const int kFocusedPressedMenuButtonImages[] =
#undef MENU_IMAGE_GRID
-// The background to use for invalid comboboxes.
-class InvalidBackground : public Background {
- public:
- InvalidBackground() {}
- virtual ~InvalidBackground() {}
-
- // Overridden from Background:
- virtual void Paint(gfx::Canvas* canvas, View* view) const OVERRIDE {
- gfx::Rect bounds(view->GetLocalBounds());
- // Inset by 2 to leave 1 empty pixel between background and border.
- bounds.Inset(2, 2, 2, 2);
- canvas->FillRect(bounds, kWarningColor);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InvalidBackground);
-};
-
// The transparent button which holds a button state but is not rendered.
class TransparentButton : public CustomButton {
public:
@@ -108,6 +93,11 @@ class TransparentButton : public CustomButton {
}
virtual ~TransparentButton() {}
+ virtual bool OnMousePressed(const ui::MouseEvent& mouse_event) OVERRIDE {
+ parent()->RequestFocus();
+ return true;
+ }
+
double GetAnimationValue() const {
return hover_animation_->GetCurrentValue();
}
@@ -238,15 +228,14 @@ const char Combobox::kViewClassName[] = "views/Combobox";
Combobox::Combobox(ui::ComboboxModel* model)
: model_(model),
- style_(STYLE_SHOW_DROP_DOWN_ON_CLICK),
+ style_(STYLE_NORMAL),
listener_(NULL),
selected_index_(model_->GetDefaultIndex()),
invalid_(false),
- disclosure_arrow_(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
- IDR_MENU_DROPARROW).ToImageSkia()),
dropdown_open_(false),
text_button_(new TransparentButton(this)),
- arrow_button_(new TransparentButton(this)) {
+ arrow_button_(new TransparentButton(this)),
+ weak_ptr_factory_(this) {
model_->AddObserver(this);
UpdateFromModel();
SetFocusable(true);
@@ -285,9 +274,9 @@ Combobox::~Combobox() {
}
// static
-const gfx::Font& Combobox::GetFont() {
+const gfx::FontList& Combobox::GetFontList() {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- return rb.GetFont(ui::ResourceBundle::BaseFont);
+ return rb.GetFontList(ui::ResourceBundle::BaseFont);
}
void Combobox::SetStyle(Style style) {
@@ -295,8 +284,11 @@ void Combobox::SetStyle(Style style) {
return;
style_ = style;
+ if (style_ == STYLE_ACTION)
+ selected_index_ = 0;
UpdateBorder();
+ UpdateFromModel();
PreferredSizeChanged();
}
@@ -307,11 +299,17 @@ void Combobox::ModelChanged() {
}
void Combobox::SetSelectedIndex(int index) {
+ if (style_ == STYLE_ACTION)
+ return;
+
selected_index_ = index;
SchedulePaint();
}
bool Combobox::SelectValue(const base::string16& value) {
+ if (style_ == STYLE_ACTION)
+ return false;
+
for (int i = 0; i < model()->GetItemCount(); ++i) {
if (value == model()->GetItemAt(i)) {
SetSelectedIndex(i);
@@ -321,7 +319,7 @@ bool Combobox::SelectValue(const base::string16& value) {
return false;
}
-void Combobox::SetAccessibleName(const string16& name) {
+void Combobox::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
@@ -331,7 +329,6 @@ void Combobox::SetInvalid(bool invalid) {
invalid_ = invalid;
- set_background(invalid_ ? new InvalidBackground() : NULL);
UpdateBorder();
SchedulePaint();
}
@@ -350,13 +347,14 @@ void Combobox::Layout() {
int arrow_button_width = 0;
switch (style_) {
- case STYLE_SHOW_DROP_DOWN_ON_CLICK: {
+ case STYLE_NORMAL: {
arrow_button_width = width();
break;
}
- case STYLE_NOTIFY_ON_CLICK: {
+ case STYLE_ACTION: {
arrow_button_width = GetDisclosureArrowLeftPadding() +
- disclosure_arrow_->width() + GetDisclosureArrowRightPadding();
+ ArrowSize().width() +
+ GetDisclosureArrowRightPadding();
text_button_width = width() - arrow_button_width;
break;
}
@@ -377,10 +375,10 @@ bool Combobox::IsCommandEnabled(int id) const {
void Combobox::ExecuteCommand(int id) {
selected_index_ = MenuCommandToIndex(id);
- OnSelectionChanged();
+ OnPerformAction();
}
-bool Combobox::GetAccelerator(int id, ui::Accelerator* accel) {
+bool Combobox::GetAccelerator(int id, ui::Accelerator* accel) const {
return false;
}
@@ -393,26 +391,27 @@ int Combobox::GetSelectedRow() {
}
void Combobox::SetSelectedRow(int row) {
+ int prev_index = selected_index_;
SetSelectedIndex(row);
+ if (selected_index_ != prev_index)
+ OnPerformAction();
}
-string16 Combobox::GetTextForRow(int row) {
- return model()->IsItemSeparatorAt(row) ? string16() : model()->GetItemAt(row);
+base::string16 Combobox::GetTextForRow(int row) {
+ return model()->IsItemSeparatorAt(row) ? base::string16() :
+ model()->GetItemAt(row);
}
////////////////////////////////////////////////////////////////////////////////
// Combobox, View overrides:
-gfx::Size Combobox::GetPreferredSize() {
- if (content_size_.IsEmpty())
- UpdateFromModel();
-
+gfx::Size Combobox::GetPreferredSize() const {
// The preferred size will drive the local bounds which in turn is used to set
// the minimum width for the dropdown list.
gfx::Insets insets = GetInsets();
int total_width = std::max(kMinComboboxWidth, content_size_.width()) +
insets.width() + GetDisclosureArrowLeftPadding() +
- disclosure_arrow_->width() + GetDisclosureArrowRightPadding();
+ ArrowSize().width() + GetDisclosureArrowRightPadding();
return gfx::Size(total_width, content_size_.height() + insets.height());
}
@@ -475,7 +474,7 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
// Click the button only when the button style mode.
case ui::VKEY_SPACE:
- if (style_ == STYLE_NOTIFY_ON_CLICK) {
+ if (style_ == STYLE_ACTION) {
// When pressing space, the click event will be raised after the key is
// released.
text_button_->SetState(Button::STATE_PRESSED);
@@ -486,9 +485,9 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
// Click the button only when the button style mode.
case ui::VKEY_RETURN:
- if (style_ != STYLE_NOTIFY_ON_CLICK)
+ if (style_ != STYLE_ACTION)
return false;
- HandleClickEvent();
+ OnPerformAction();
break;
default:
@@ -498,34 +497,35 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
if (show_menu) {
UpdateFromModel();
ShowDropDownMenu(ui::MENU_SOURCE_KEYBOARD);
- } else if (new_index != selected_index_ && new_index != kNoSelection) {
+ } else if (new_index != selected_index_ && new_index != kNoSelection &&
+ style_ != STYLE_ACTION) {
DCHECK(!model()->IsItemSeparatorAt(new_index));
selected_index_ = new_index;
- OnSelectionChanged();
+ OnPerformAction();
}
return true;
}
bool Combobox::OnKeyReleased(const ui::KeyEvent& e) {
- if (style_ != STYLE_NOTIFY_ON_CLICK)
+ if (style_ != STYLE_ACTION)
return false; // crbug.com/127520
- if (e.key_code() == ui::VKEY_SPACE)
- HandleClickEvent();
+ if (e.key_code() == ui::VKEY_SPACE && style_ == STYLE_ACTION)
+ OnPerformAction();
return false;
}
void Combobox::OnPaint(gfx::Canvas* canvas) {
switch (style_) {
- case STYLE_SHOW_DROP_DOWN_ON_CLICK: {
+ case STYLE_NORMAL: {
OnPaintBackground(canvas);
PaintText(canvas);
OnPaintBorder(canvas);
break;
}
- case STYLE_NOTIFY_ON_CLICK: {
+ case STYLE_ACTION: {
PaintButtons(canvas);
PaintText(canvas);
break;
@@ -548,23 +548,27 @@ void Combobox::OnBlur() {
SchedulePaint();
}
-void Combobox::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_COMBOBOX;
+void Combobox::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_COMBO_BOX;
state->name = accessible_name_;
state->value = model_->GetItemAt(selected_index_);
state->index = selected_index_;
state->count = model_->GetItemCount();
}
-void Combobox::OnModelChanged() {
+void Combobox::OnComboboxModelChanged(ui::ComboboxModel* model) {
+ DCHECK_EQ(model, model_);
ModelChanged();
}
void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
+ if (!enabled())
+ return;
+
RequestFocus();
if (sender == text_button_) {
- HandleClickEvent();
+ OnPerformAction();
} else {
DCHECK_EQ(arrow_button_, sender);
// TODO(hajimehoshi): Fix the problem that the arrow button blinks when
@@ -583,40 +587,50 @@ void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
}
void Combobox::UpdateFromModel() {
- int max_width = 0;
- const gfx::Font& font = Combobox::GetFont();
+ const gfx::FontList& font_list = Combobox::GetFontList();
MenuItemView* menu = new MenuItemView(this);
// MenuRunner owns |menu|.
dropdown_list_menu_runner_.reset(new MenuRunner(menu));
int num_items = model()->GetItemCount();
+ int width = 0;
+ bool text_item_appended = false;
for (int i = 0; i < num_items; ++i) {
+ // When STYLE_ACTION is used, the first item and the following separators
+ // are not added to the dropdown menu. It is assumed that the first item is
+ // always selected and rendered on the top of the action button.
if (model()->IsItemSeparatorAt(i)) {
- menu->AppendSeparator();
+ if (text_item_appended || style_ != STYLE_ACTION)
+ menu->AppendSeparator();
continue;
}
- string16 text = model()->GetItemAt(i);
+ base::string16 text = model()->GetItemAt(i);
// Inserting the Unicode formatting characters if necessary so that the
// text is displayed correctly in right-to-left UIs.
base::i18n::AdjustStringForLocaleDirection(&text);
- menu->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL);
- max_width = std::max(max_width, font.GetStringWidth(text));
+ if (style_ != STYLE_ACTION || i > 0) {
+ menu->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL);
+ text_item_appended = true;
+ }
+
+ if (style_ != STYLE_ACTION || i == selected_index_)
+ width = std::max(width, gfx::GetStringWidth(text, font_list));
}
- content_size_.SetSize(max_width, font.GetHeight());
+ content_size_.SetSize(width, font_list.GetHeight());
}
void Combobox::UpdateBorder() {
- FocusableBorder* border = new FocusableBorder();
- if (style_ == STYLE_NOTIFY_ON_CLICK)
+ scoped_ptr<FocusableBorder> border(new FocusableBorder());
+ if (style_ == STYLE_ACTION)
border->SetInsets(8, 13, 8, 13);
if (invalid_)
border->SetColor(kWarningColor);
- set_border(border);
+ SetBorder(border.PassAs<Border>());
}
void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const {
@@ -632,45 +646,52 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
int x = insets.left();
int y = insets.top();
int text_height = height() - insets.height();
- SkColor text_color = invalid() ? kInvalidTextColor :
- GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_LabelEnabledColor);
+ SkColor text_color = GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_LabelEnabledColor);
DCHECK_GE(selected_index_, 0);
DCHECK_LT(selected_index_, model()->GetItemCount());
if (selected_index_ < 0 || selected_index_ > model()->GetItemCount())
selected_index_ = 0;
- string16 text = model()->GetItemAt(selected_index_);
+ base::string16 text = model()->GetItemAt(selected_index_);
- int disclosure_arrow_offset = width() - disclosure_arrow_->width() -
+ gfx::Size arrow_size = ArrowSize();
+ int disclosure_arrow_offset = width() - arrow_size.width() -
GetDisclosureArrowLeftPadding() - GetDisclosureArrowRightPadding();
- const gfx::Font& font = Combobox::GetFont();
- int text_width = font.GetStringWidth(text);
+ const gfx::FontList& font_list = Combobox::GetFontList();
+ int text_width = gfx::GetStringWidth(text, font_list);
if ((text_width + insets.width()) > disclosure_arrow_offset)
text_width = disclosure_arrow_offset - insets.width();
gfx::Rect text_bounds(x, y, text_width, text_height);
AdjustBoundsForRTLUI(&text_bounds);
- canvas->DrawStringInt(text, font, text_color, text_bounds);
+ canvas->DrawStringRect(text, font_list, text_color, text_bounds);
int arrow_x = disclosure_arrow_offset + GetDisclosureArrowLeftPadding();
gfx::Rect arrow_bounds(arrow_x,
- height() / 2 - disclosure_arrow_->height() / 2,
- disclosure_arrow_->width(),
- disclosure_arrow_->height());
+ height() / 2 - arrow_size.height() / 2,
+ arrow_size.width(),
+ arrow_size.height());
AdjustBoundsForRTLUI(&arrow_bounds);
- SkPaint paint;
- // This makes the arrow subtractive.
- if (invalid())
- paint.setXfermodeMode(SkXfermode::kDstOut_Mode);
- canvas->DrawImageInt(*disclosure_arrow_, arrow_bounds.x(), arrow_bounds.y(),
- paint);
+ // TODO(estade): hack alert! Remove this direct call into CommonTheme. For now
+ // STYLE_ACTION isn't properly themed so we have to override the NativeTheme
+ // behavior. See crbug.com/384071
+ if (style_ == STYLE_ACTION) {
+ ui::CommonThemePaintComboboxArrow(canvas->sk_canvas(), arrow_bounds);
+ } else {
+ ui::NativeTheme::ExtraParams ignored;
+ GetNativeTheme()->Paint(canvas->sk_canvas(),
+ ui::NativeTheme::kComboboxArrow,
+ ui::NativeTheme::kNormal,
+ arrow_bounds,
+ ignored);
+ }
}
void Combobox::PaintButtons(gfx::Canvas* canvas) {
- DCHECK(style_ == STYLE_NOTIFY_ON_CLICK);
+ DCHECK(style_ == STYLE_ACTION);
gfx::ScopedCanvas scoped_canvas(canvas);
if (base::i18n::IsRTL()) {
@@ -739,10 +760,12 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
gfx::Rect lb = GetLocalBounds();
gfx::Point menu_position(lb.origin());
- // Inset the menu's requested position so the border of the menu lines up
- // with the border of the combobox.
- menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft);
- menu_position.set_y(menu_position.y() + kMenuBorderWidthTop);
+ if (style_ == STYLE_NORMAL) {
+ // Inset the menu's requested position so the border of the menu lines up
+ // with the border of the combobox.
+ menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft);
+ menu_position.set_y(menu_position.y() + kMenuBorderWidthTop);
+ }
lb.set_width(lb.width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight));
View::ConvertPointToScreen(this, &menu_position);
@@ -757,8 +780,10 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
arrow_button_->SetState(Button::STATE_PRESSED);
}
dropdown_open_ = true;
+ MenuAnchorPosition anchor_position =
+ style_ == STYLE_ACTION ? MENU_ANCHOR_TOPRIGHT : MENU_ANCHOR_TOPLEFT;
if (dropdown_list_menu_runner_->RunMenuAt(GetWidget(), NULL, bounds,
- MenuItemView::TOPLEFT, source_type,
+ anchor_position, source_type,
MenuRunner::COMBOBOX) ==
MenuRunner::MENU_DELETED) {
return;
@@ -774,12 +799,17 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
SetMouseHandler(NULL);
}
-void Combobox::OnSelectionChanged() {
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, false);
+void Combobox::OnPerformAction() {
+ NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, false);
SchedulePaint();
+
+ // This combobox may be deleted by the listener.
+ base::WeakPtr<Combobox> weak_ptr = weak_ptr_factory_.GetWeakPtr();
if (listener_)
- listener_->OnSelectedIndexChanged(this);
- // |this| may now be deleted.
+ listener_->OnPerformAction(this);
+
+ if (weak_ptr && style_ == STYLE_ACTION)
+ selected_index_ = 0;
}
int Combobox::MenuCommandToIndex(int menu_command_id) const {
@@ -792,9 +822,9 @@ int Combobox::MenuCommandToIndex(int menu_command_id) const {
int Combobox::GetDisclosureArrowLeftPadding() const {
switch (style_) {
- case STYLE_SHOW_DROP_DOWN_ON_CLICK:
+ case STYLE_NORMAL:
return kDisclosureArrowLeftPadding;
- case STYLE_NOTIFY_ON_CLICK:
+ case STYLE_ACTION:
return kDisclosureArrowButtonLeftPadding;
}
NOTREACHED();
@@ -803,21 +833,31 @@ int Combobox::GetDisclosureArrowLeftPadding() const {
int Combobox::GetDisclosureArrowRightPadding() const {
switch (style_) {
- case STYLE_SHOW_DROP_DOWN_ON_CLICK:
+ case STYLE_NORMAL:
return kDisclosureArrowRightPadding;
- case STYLE_NOTIFY_ON_CLICK:
+ case STYLE_ACTION:
return kDisclosureArrowButtonRightPadding;
}
NOTREACHED();
return 0;
}
-void Combobox::HandleClickEvent() {
- if (style_ != STYLE_NOTIFY_ON_CLICK)
- return;
-
- if (listener_)
- listener_->OnComboboxTextButtonClicked(this);
+gfx::Size Combobox::ArrowSize() const {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // TODO(estade): hack alert! This should always use GetNativeTheme(). For now
+ // STYLE_ACTION isn't properly themed so we have to override the NativeTheme
+ // behavior. See crbug.com/384071
+ const ui::NativeTheme* native_theme_for_arrow = style_ == STYLE_ACTION ?
+ ui::NativeTheme::instance() :
+ GetNativeTheme();
+#else
+ const ui::NativeTheme* native_theme_for_arrow = GetNativeTheme();
+#endif
+
+ ui::NativeTheme::ExtraParams ignored;
+ return native_theme_for_arrow->GetPartSize(ui::NativeTheme::kComboboxArrow,
+ ui::NativeTheme::kNormal,
+ ignored);
}
} // namespace views
diff --git a/chromium/ui/views/controls/combobox/combobox.h b/chromium/ui/views/controls/combobox/combobox.h
index 8ec45c9e211..22781a8ab1f 100644
--- a/chromium/ui/views/controls/combobox/combobox.h
+++ b/chromium/ui/views/controls/combobox/combobox.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "ui/base/models/combobox_model_observer.h"
#include "ui/gfx/animation/animation_delegate.h"
@@ -16,7 +17,7 @@
#include "ui/views/controls/prefix_delegate.h"
namespace gfx {
-class Font;
+class FontList;
class SlideAnimation;
}
@@ -36,10 +37,14 @@ class Painter;
class PrefixSelector;
// A non-editable combobox (aka a drop-down list or selector).
-// Combobox has two distinct parts, the drop down arrow and the text. When the
-// user clicks on the text the drop down is either shown
-// (STYLE_SHOW_DROP_DOWN_ON_CLICK) or the listener is notified
-// (STYLE_NOTIFY_ON_CLICK).
+// Combobox has two distinct parts, the drop down arrow and the text. Combobox
+// offers two distinct behaviors:
+// * STYLE_NORMAL: typical combobox, clicking on the text and/or button shows
+// the drop down, arrow keys change selection, selected index can be changed by
+// the user to something other than the first item.
+// * STYLE_ACTION: clicking on the text notifies the listener. The menu can be
+// shown only by clicking on the arrow. The selected index is always reverted to
+// 0 after the listener is notified.
class VIEWS_EXPORT Combobox : public MenuDelegate,
public PrefixDelegate,
public ui::ComboboxModelObserver,
@@ -47,8 +52,8 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
public:
// The style of the combobox.
enum Style {
- STYLE_SHOW_DROP_DOWN_ON_CLICK,
- STYLE_NOTIFY_ON_CLICK,
+ STYLE_NORMAL,
+ STYLE_ACTION,
};
// The combobox's class name.
@@ -58,7 +63,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
explicit Combobox(ui::ComboboxModel* model);
virtual ~Combobox();
- static const gfx::Font& GetFont();
+ static const gfx::FontList& GetFontList();
// Sets the listener which will be called when a selection has been made.
void set_listener(ComboboxListener* listener) { listener_ = listener; }
@@ -79,7 +84,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
ui::ComboboxModel* model() const { return model_; }
// Set the accessible name of the combobox.
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
// Visually marks the combobox as having an invalid value selected.
// When invalid, it paints with white text on a red background.
@@ -88,7 +93,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
bool invalid() const { return invalid_; }
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE;
@@ -96,7 +101,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
virtual void Layout() OVERRIDE;
@@ -104,23 +109,26 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
virtual bool IsItemChecked(int id) const OVERRIDE;
virtual bool IsCommandEnabled(int id) const OVERRIDE;
virtual void ExecuteCommand(int id) OVERRIDE;
- virtual bool GetAccelerator(int id, ui::Accelerator* accelerator) OVERRIDE;
+ virtual bool GetAccelerator(int id,
+ ui::Accelerator* accelerator) const OVERRIDE;
// Overridden from PrefixDelegate:
virtual int GetRowCount() OVERRIDE;
virtual int GetSelectedRow() OVERRIDE;
virtual void SetSelectedRow(int row) OVERRIDE;
- virtual string16 GetTextForRow(int row) OVERRIDE;
+ virtual base::string16 GetTextForRow(int row) OVERRIDE;
// Overriden from ComboboxModelObserver:
- virtual void OnModelChanged() OVERRIDE;
+ virtual void OnComboboxModelChanged(ui::ComboboxModel* model) OVERRIDE;
// Overriden from ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
private:
FRIEND_TEST_ALL_PREFIXES(ComboboxTest, Click);
+ FRIEND_TEST_ALL_PREFIXES(ComboboxTest, ClickButDisabled);
FRIEND_TEST_ALL_PREFIXES(ComboboxTest, NotifyOnClickWithMouse);
+ FRIEND_TEST_ALL_PREFIXES(ComboboxTest, ContentWidth);
// Updates the combobox's content from its model.
void UpdateFromModel();
@@ -141,7 +149,9 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
void ShowDropDownMenu(ui::MenuSourceType source_type);
// Called when the selection is changed by the user.
- void OnSelectionChanged();
+ void OnPerformAction();
+ void NotifyPerformAction();
+ void AfterPerformAction();
// Converts a menu command ID to a menu item index.
int MenuCommandToIndex(int menu_command_id) const;
@@ -149,6 +159,9 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
int GetDisclosureArrowLeftPadding() const;
int GetDisclosureArrowRightPadding() const;
+ // Returns the size of the disclosure arrow.
+ gfx::Size ArrowSize() const;
+
// Handles the clicking event.
void HandleClickEvent();
@@ -168,14 +181,11 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
bool invalid_;
// The accessible name of this combobox.
- string16 accessible_name_;
+ base::string16 accessible_name_;
// A helper used to select entries by keyboard input.
scoped_ptr<PrefixSelector> selector_;
- // The disclosure arrow next to the currently selected item from the list.
- const gfx::ImageSkia* disclosure_arrow_;
-
// Responsible for showing the context menu.
scoped_ptr<MenuRunner> dropdown_list_menu_runner_;
@@ -191,7 +201,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
base::Time closed_time_;
// The maximum dimensions of the content in the dropdown
- gfx::Size content_size_;
+ mutable gfx::Size content_size_;
// The painters or images that are used when |style_| is STYLE_BUTTONS. The
// first index means the state of unfocused or focused.
@@ -209,6 +219,9 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
CustomButton* text_button_;
CustomButton* arrow_button_;
+ // Used for making calbacks.
+ base::WeakPtrFactory<Combobox> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(Combobox);
};
diff --git a/chromium/ui/views/controls/combobox/combobox_listener.h b/chromium/ui/views/controls/combobox/combobox_listener.h
index 2609f647023..2522e03c7d8 100644
--- a/chromium/ui/views/controls/combobox/combobox_listener.h
+++ b/chromium/ui/views/controls/combobox/combobox_listener.h
@@ -5,19 +5,24 @@
#ifndef UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_LISTENER_H_
#define UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_LISTENER_H_
+#include "ui/views/views_export.h"
+
namespace views {
class Combobox;
-// An interface implemented by an object to let it know that the selected index
-// has changed.
-class ComboboxListener {
+// Interface used to notify consumers when something interesting happens to a
+// Combobox.
+class VIEWS_EXPORT ComboboxListener {
public:
- virtual void OnSelectedIndexChanged(Combobox* combobox) = 0;
-
- // Handles when the combobox's style is the button style and the button is
- // clicked.
- virtual void OnComboboxTextButtonClicked(Combobox* combobox) {}
+ // Invoked when the user does the appropriate gesture that some action should
+ // be performed. For both STYLE_NORMAL and STYLE_ACTION this is invoked if the
+ // user clicks on the menu button and then clicks an item. For STYLE_NORMAL
+ // this is also invoked when the menu is not showing and the does a gesture to
+ // change the selection (for example, presses the home or end keys). This is
+ // not invoked when the menu is shown and the user changes the selection
+ // without closing the menu.
+ virtual void OnPerformAction(Combobox* combobox) = 0;
protected:
virtual ~ComboboxListener() {}
diff --git a/chromium/ui/views/controls/combobox/combobox_unittest.cc b/chromium/ui/views/controls/combobox/combobox_unittest.cc
index 7b68c4578e3..67625a2aea1 100644
--- a/chromium/ui/views/controls/combobox/combobox_unittest.cc
+++ b/chromium/ui/views/controls/combobox/combobox_unittest.cc
@@ -8,8 +8,10 @@
#include "base/basictypes.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/ime/text_input_client.h"
#include "ui/base/models/combobox_model.h"
#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/controls/menu/menu_runner.h"
@@ -19,6 +21,8 @@
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace {
@@ -27,15 +31,14 @@ namespace {
// shown or not.
class TestMenuRunnerHandler : public MenuRunnerHandler {
public:
- TestMenuRunnerHandler()
- : executed_(false) {}
+ TestMenuRunnerHandler() : executed_(false) {}
bool executed() const { return executed_; }
virtual MenuRunner::RunResult RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
ui::MenuSourceType source_type,
int32 types) OVERRIDE {
executed_ = true;
@@ -55,8 +58,7 @@ class TestCombobox : public Combobox {
explicit TestCombobox(ui::ComboboxModel* model)
: Combobox(model),
key_handled_(false),
- key_received_(false) {
- }
+ key_received_(false) {}
virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE {
key_received_ = true;
@@ -94,7 +96,7 @@ class TestComboboxModel : public ui::ComboboxModel {
virtual int GetItemCount() const OVERRIDE {
return 10;
}
- virtual string16 GetItemAt(int index) OVERRIDE {
+ virtual base::string16 GetItemAt(int index) OVERRIDE {
if (IsItemSeparatorAt(index)) {
NOTREACHED();
return ASCIIToUTF16("SEPARATOR");
@@ -115,13 +117,35 @@ class TestComboboxModel : public ui::ComboboxModel {
DISALLOW_COPY_AND_ASSIGN(TestComboboxModel);
};
+// A combobox model which refers to a vector.
+class VectorComboboxModel : public ui::ComboboxModel {
+ public:
+ explicit VectorComboboxModel(std::vector<std::string>* values)
+ : values_(values) {}
+ virtual ~VectorComboboxModel() {}
+
+ // ui::ComboboxModel:
+ virtual int GetItemCount() const OVERRIDE {
+ return (int)values_->size();
+ }
+ virtual base::string16 GetItemAt(int index) OVERRIDE {
+ return ASCIIToUTF16(values_->at(index));
+ }
+ virtual bool IsItemSeparatorAt(int index) OVERRIDE {
+ return false;
+ }
+
+ private:
+ std::vector<std::string>* values_;
+};
+
class EvilListener : public ComboboxListener {
public:
- EvilListener() : deleted_(false) {};
+ EvilListener() : deleted_(false) {}
virtual ~EvilListener() {};
// ComboboxListener:
- virtual void OnSelectedIndexChanged(Combobox* combobox) OVERRIDE {
+ virtual void OnPerformAction(Combobox* combobox) OVERRIDE {
delete combobox;
deleted_ = true;
}
@@ -136,31 +160,29 @@ class EvilListener : public ComboboxListener {
class TestComboboxListener : public views::ComboboxListener {
public:
- TestComboboxListener()
- : on_selected_index_changed_called_(false),
- on_combobox_text_button_clicked_called_(false) {
- }
+ TestComboboxListener() : perform_action_index_(-1), actions_performed_(0) {}
virtual ~TestComboboxListener() {}
- virtual void OnSelectedIndexChanged(views::Combobox* combobox) OVERRIDE {
- on_selected_index_changed_called_ = true;
+ virtual void OnPerformAction(views::Combobox* combobox) OVERRIDE {
+ perform_action_index_ = combobox->selected_index();
+ actions_performed_++;
}
- virtual void OnComboboxTextButtonClicked(views::Combobox* combobox) OVERRIDE {
- on_combobox_text_button_clicked_called_ = true;
+ int perform_action_index() const {
+ return perform_action_index_;
}
- bool on_selected_index_changed_called() const {
- return on_selected_index_changed_called_;
+ bool on_perform_action_called() const {
+ return actions_performed_ > 0;
}
- bool on_combobox_text_button_clicked_called() const {
- return on_combobox_text_button_clicked_called_;
+ int actions_performed() const {
+ return actions_performed_;
}
private:
- bool on_selected_index_changed_called_;
- bool on_combobox_text_button_clicked_called_;
+ int perform_action_index_;
+ int actions_performed_;
private:
DISALLOW_COPY_AND_ASSIGN(TestComboboxListener);
@@ -170,7 +192,7 @@ class TestComboboxListener : public views::ComboboxListener {
class ComboboxTest : public ViewsTestBase {
public:
- ComboboxTest() : widget_(NULL), combobox_(NULL), input_method_(NULL) {}
+ ComboboxTest() : widget_(NULL), combobox_(NULL) {}
virtual void TearDown() OVERRIDE {
if (widget_)
@@ -193,11 +215,10 @@ class ComboboxTest : public ViewsTestBase {
widget_->SetContentsView(container);
container->AddChildView(combobox_);
- input_method_ = new MockInputMethod();
- widget_->ReplaceInputMethod(input_method_);
+ widget_->ReplaceInputMethod(new MockInputMethod);
// Assumes the Widget is always focused.
- input_method_->OnFocus();
+ widget_->GetInputMethod()->OnFocus();
combobox_->RequestFocus();
combobox_->SizeToPreferredSize();
@@ -210,7 +231,7 @@ class ComboboxTest : public ViewsTestBase {
void SendKeyEventWithType(ui::KeyboardCode key_code, ui::EventType type) {
ui::KeyEvent event(type, key_code, 0, false);
- input_method_->DispatchKeyEvent(event);
+ widget_->GetInputMethod()->DispatchKeyEvent(event);
}
View* GetFocusedView() {
@@ -220,10 +241,12 @@ class ComboboxTest : public ViewsTestBase {
void PerformClick(const gfx::Point& point) {
ui::MouseEvent pressed_event = ui::MouseEvent(ui::ET_MOUSE_PRESSED, point,
point,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
widget_->OnMouseEvent(&pressed_event);
ui::MouseEvent released_event = ui::MouseEvent(ui::ET_MOUSE_RELEASED, point,
point,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
widget_->OnMouseEvent(&released_event);
}
@@ -236,9 +259,6 @@ class ComboboxTest : public ViewsTestBase {
// Combobox does not take ownership of the model, hence it needs to be scoped.
scoped_ptr<TestComboboxModel> model_;
-
- // For testing input method related behaviors.
- MockInputMethod* input_method_;
};
TEST_F(ComboboxTest, KeyTest) {
@@ -435,15 +455,48 @@ TEST_F(ComboboxTest, SelectValue) {
EXPECT_EQ(1, combobox_->selected_index());
EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("BANANAS")));
EXPECT_EQ(1, combobox_->selected_index());
+
+ // With the action style, the selected index is always 0.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
+ EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
+ EXPECT_EQ(0, combobox_->selected_index());
+ EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("JELLY")));
+ EXPECT_EQ(0, combobox_->selected_index());
+ EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("BANANAS")));
+ EXPECT_EQ(0, combobox_->selected_index());
+}
+
+TEST_F(ComboboxTest, SelectIndexActionStyle) {
+ InitCombobox();
+
+ // With the action style, the selected index is always 0.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
+ combobox_->SetSelectedIndex(1);
+ EXPECT_EQ(0, combobox_->selected_index());
+ combobox_->SetSelectedIndex(2);
+ EXPECT_EQ(0, combobox_->selected_index());
+ combobox_->SetSelectedIndex(3);
+ EXPECT_EQ(0, combobox_->selected_index());
}
TEST_F(ComboboxTest, ListenerHandlesDelete) {
TestComboboxModel model;
- TestCombobox* combobox = new TestCombobox(&model); // Deleted on change.
- EvilListener evil_listener;
- combobox->set_listener(&evil_listener);
+
+ // |combobox| will be deleted on change.
+ TestCombobox* combobox = new TestCombobox(&model);
+ scoped_ptr<EvilListener> evil_listener(new EvilListener());
+ combobox->set_listener(evil_listener.get());
+ ASSERT_NO_FATAL_FAILURE(combobox->ExecuteCommand(2));
+ EXPECT_TRUE(evil_listener->deleted());
+
+ // With STYLE_ACTION
+ // |combobox| will be deleted on change.
+ combobox = new TestCombobox(&model);
+ evil_listener.reset(new EvilListener());
+ combobox->set_listener(evil_listener.get());
+ combobox->SetStyle(Combobox::STYLE_ACTION);
ASSERT_NO_FATAL_FAILURE(combobox->ExecuteCommand(2));
- EXPECT_TRUE(evil_listener.deleted());
+ EXPECT_TRUE(evil_listener->deleted());
}
TEST_F(ComboboxTest, Click) {
@@ -462,24 +515,46 @@ TEST_F(ComboboxTest, Click) {
test_api.SetMenuRunnerHandler(menu_runner_handler.Pass());
PerformClick(gfx::Point(combobox_->x() + 1,
combobox_->y() + combobox_->height() / 2));
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
EXPECT_TRUE(test_menu_runner_handler->executed());
}
+TEST_F(ComboboxTest, ClickButDisabled) {
+ InitCombobox();
+
+ TestComboboxListener listener;
+ combobox_->set_listener(&listener);
+
+ combobox_->Layout();
+ combobox_->SetEnabled(false);
+
+ // Click the left side, but nothing happens since the combobox is disabled.
+ TestMenuRunnerHandler* test_menu_runner_handler = new TestMenuRunnerHandler();
+ scoped_ptr<MenuRunnerHandler> menu_runner_handler(test_menu_runner_handler);
+ test::MenuRunnerTestAPI test_api(
+ combobox_->dropdown_list_menu_runner_.get());
+ test_api.SetMenuRunnerHandler(menu_runner_handler.Pass());
+ PerformClick(gfx::Point(combobox_->x() + 1,
+ combobox_->y() + combobox_->height() / 2));
+ EXPECT_FALSE(listener.on_perform_action_called());
+ EXPECT_FALSE(test_menu_runner_handler->executed());
+}
+
TEST_F(ComboboxTest, NotifyOnClickWithReturnKey) {
InitCombobox();
TestComboboxListener listener;
combobox_->set_listener(&listener);
- // With STYLE_SHOW_DROP_DOWN_ON_CLICK, the click event is ignored.
+ // With STYLE_NORMAL, the click event is ignored.
SendKeyEvent(ui::VKEY_RETURN);
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
- // With STYLE_NOTIFY_ON_CLICK, the click event is notified.
- combobox_->SetStyle(Combobox::STYLE_NOTIFY_ON_CLICK);
+ // With STYLE_ACTION, the click event is notified.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
SendKeyEvent(ui::VKEY_RETURN);
- EXPECT_TRUE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_TRUE(listener.on_perform_action_called());
+ EXPECT_EQ(0, listener.perform_action_index());
}
TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) {
@@ -488,18 +563,19 @@ TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) {
TestComboboxListener listener;
combobox_->set_listener(&listener);
- // With STYLE_SHOW_DROP_DOWN_ON_CLICK, the click event is ignored.
+ // With STYLE_NORMAL, the click event is ignored.
SendKeyEvent(ui::VKEY_SPACE);
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED);
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
- // With STYLE_NOTIFY_ON_CLICK, the click event is notified after releasing.
- combobox_->SetStyle(Combobox::STYLE_NOTIFY_ON_CLICK);
+ // With STYLE_ACTION, the click event is notified after releasing.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
SendKeyEvent(ui::VKEY_SPACE);
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED);
- EXPECT_TRUE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_TRUE(listener.on_perform_action_called());
+ EXPECT_EQ(0, listener.perform_action_index());
}
TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
@@ -508,7 +584,7 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
TestComboboxListener listener;
combobox_->set_listener(&listener);
- combobox_->SetStyle(Combobox::STYLE_NOTIFY_ON_CLICK);
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
combobox_->Layout();
// Click the right side (arrow button). The menu is shown.
@@ -520,7 +596,7 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
PerformClick(gfx::Point(combobox_->x() + combobox_->width() - 1,
combobox_->y() + combobox_->height() / 2));
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
EXPECT_TRUE(test_menu_runner_handler->executed());
// Click the left side (text button). The click event is notified.
@@ -531,8 +607,9 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
test_api->SetMenuRunnerHandler(menu_runner_handler.Pass());
PerformClick(gfx::Point(combobox_->x() + 1,
combobox_->y() + combobox_->height() / 2));
- EXPECT_TRUE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_TRUE(listener.on_perform_action_called());
EXPECT_FALSE(test_menu_runner_handler->executed());
+ EXPECT_EQ(0, listener.perform_action_index());
}
TEST_F(ComboboxTest, ConsumingPressKeyEvents) {
@@ -543,13 +620,74 @@ TEST_F(ComboboxTest, ConsumingPressKeyEvents) {
EXPECT_FALSE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, false)));
- // When the combobox's style is STYLE_NOTIFY_ON_CLICK, pressing events of
- // a space key or an enter key will be consumed.
- combobox_->SetStyle(Combobox::STYLE_NOTIFY_ON_CLICK);
+ // When the combobox's style is STYLE_ACTION, pressing events of a space key
+ // or an enter key will be consumed.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
EXPECT_TRUE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0, false)));
EXPECT_TRUE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, false)));
}
+TEST_F(ComboboxTest, ContentWidth) {
+ std::vector<std::string> values;
+ VectorComboboxModel model(&values);
+ TestCombobox combobox(&model);
+
+ std::string long_item = "this is the long item";
+ std::string short_item = "s";
+
+ values.resize(1);
+ values[0] = long_item;
+ combobox.ModelChanged();
+
+ const int long_item_width = combobox.content_size_.width();
+
+ values[0] = short_item;
+ combobox.ModelChanged();
+
+ const int short_item_width = combobox.content_size_.width();
+
+ values.resize(2);
+ values[0] = short_item;
+ values[1] = long_item;
+ combobox.ModelChanged();
+
+ // When the style is STYLE_NORMAL, the width will fit with the longest item.
+ combobox.SetStyle(Combobox::STYLE_NORMAL);
+ EXPECT_EQ(long_item_width, combobox.content_size_.width());
+
+ // When the style is STYLE_ACTION, the width will fit with the first items'
+ // width.
+ combobox.SetStyle(Combobox::STYLE_ACTION);
+ EXPECT_EQ(short_item_width, combobox.content_size_.width());
+}
+
+TEST_F(ComboboxTest, TypingPrefixNotifiesListener) {
+ InitCombobox();
+
+ TestComboboxListener listener;
+ combobox_->set_listener(&listener);
+
+ // Type the first character of the second menu item ("JELLY").
+ combobox_->GetTextInputClient()->InsertChar('J', ui::EF_NONE);
+ EXPECT_EQ(1, listener.actions_performed());
+ EXPECT_EQ(1, listener.perform_action_index());
+
+ // Type the second character of "JELLY", item shouldn't change and
+ // OnPerformAction() shouldn't be re-called.
+ combobox_->GetTextInputClient()->InsertChar('E', ui::EF_NONE);
+ EXPECT_EQ(1, listener.actions_performed());
+ EXPECT_EQ(1, listener.perform_action_index());
+
+ // Clears the typed text.
+ combobox_->OnBlur();
+
+ // Type the first character of "PEANUT BUTTER", which should change the
+ // selected index and perform an action.
+ combobox_->GetTextInputClient()->InsertChar('P', ui::EF_NONE);
+ EXPECT_EQ(2, listener.actions_performed());
+ EXPECT_EQ(2, listener.perform_action_index());
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/image_view.cc b/chromium/ui/views/controls/image_view.cc
index 2bbf91cab9e..5b758f8e1c7 100644
--- a/chromium/ui/views/controls/image_view.cc
+++ b/chromium/ui/views/controls/image_view.cc
@@ -7,13 +7,25 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkPaint.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/insets.h"
#include "ui/views/painter.h"
namespace views {
+namespace {
+
+// Returns the pixels for the bitmap in |image| at scale |image_scale|.
+void* GetBitmapPixels(const gfx::ImageSkia& img, float image_scale) {
+ DCHECK_NE(0.0f, image_scale);
+ const SkBitmap& bitmap = img.GetRepresentation(image_scale).sk_bitmap();
+ SkAutoLockPixels pixel_lock(bitmap);
+ return bitmap.getPixels();
+}
+
+} // namespace
+
ImageView::ImageView()
: image_size_set_(false),
horiz_alignment_(CENTER),
@@ -58,7 +70,7 @@ void ImageView::SetImageSize(const gfx::Size& image_size) {
PreferredSizeChanged();
}
-bool ImageView::GetImageSize(gfx::Size* image_size) {
+bool ImageView::GetImageSize(gfx::Size* image_size) const {
DCHECK(image_size);
if (image_size_set_)
*image_size = image_size_;
@@ -79,7 +91,7 @@ void ImageView::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
focus_painter_ = focus_painter.Pass();
}
-gfx::Size ImageView::GetPreferredSize() {
+gfx::Size ImageView::GetPreferredSize() const {
gfx::Insets insets = GetInsets();
if (image_size_set_) {
gfx::Size image_size;
@@ -99,8 +111,7 @@ bool ImageView::IsImageEqual(const gfx::ImageSkia& img) const {
// the backing store but also the pixels of the last image we painted.
return image_.BackedBySameObjectAs(img) &&
last_paint_scale_ != 0.0f &&
- last_painted_bitmap_pixels_ ==
- img.GetRepresentation(last_paint_scale_).sk_bitmap().getPixels();
+ last_painted_bitmap_pixels_ == GetBitmapPixels(img, last_paint_scale_);
}
gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const {
@@ -150,8 +161,8 @@ void ImageView::OnPaint(gfx::Canvas* canvas) {
Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
}
-void ImageView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_GRAPHIC;
+void ImageView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_IMAGE;
state->name = tooltip_text_;
}
@@ -177,15 +188,16 @@ ImageView::Alignment ImageView::GetVerticalAlignment() const {
return vert_alignment_;
}
-void ImageView::SetTooltipText(const string16& tooltip) {
+void ImageView::SetTooltipText(const base::string16& tooltip) {
tooltip_text_ = tooltip;
}
-string16 ImageView::GetTooltipText() const {
+base::string16 ImageView::GetTooltipText() const {
return tooltip_text_;
}
-bool ImageView::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool ImageView::GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const {
if (tooltip_text_.empty())
return false;
@@ -193,11 +205,10 @@ bool ImageView::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
return true;
}
-bool ImageView::HitTestRect(const gfx::Rect& rect) const {
- return interactive_ ? View::HitTestRect(rect) : false;
+bool ImageView::CanProcessEventsWithinSubtree() const {
+ return interactive_;
}
-
void ImageView::OnPaintImage(gfx::Canvas* canvas) {
last_paint_scale_ = canvas->image_scale();
last_painted_bitmap_pixels_ = NULL;
@@ -212,15 +223,14 @@ void ImageView::OnPaintImage(gfx::Canvas* canvas) {
if (image_bounds.size() != gfx::Size(image_.width(), image_.height())) {
// Resize case
SkPaint paint;
- paint.setFilterBitmap(true);
+ paint.setFilterLevel(SkPaint::kLow_FilterLevel);
canvas->DrawImageInt(image_, 0, 0, image_.width(), image_.height(),
image_bounds.x(), image_bounds.y(), image_bounds.width(),
image_bounds.height(), true, paint);
} else {
canvas->DrawImageInt(image_, image_bounds.x(), image_bounds.y());
}
- last_painted_bitmap_pixels_ =
- image_.GetRepresentation(last_paint_scale_).sk_bitmap().getPixels();
+ last_painted_bitmap_pixels_ = GetBitmapPixels(image_, last_paint_scale_);
}
} // namespace views
diff --git a/chromium/ui/views/controls/image_view.h b/chromium/ui/views/controls/image_view.h
index b0f4ce852ff..a05b106ecfa 100644
--- a/chromium/ui/views/controls/image_view.h
+++ b/chromium/ui/views/controls/image_view.h
@@ -55,7 +55,7 @@ class VIEWS_EXPORT ImageView : public View {
// Return the preferred size for the receiving view. Returns false if the
// preferred size is not defined, which means that the view uses the image
// size.
- bool GetImageSize(gfx::Size* image_size);
+ bool GetImageSize(gfx::Size* image_size) const;
// Returns the actual bounds of the visible image inside the view.
gfx::Rect GetImageBounds() const;
@@ -72,22 +72,22 @@ class VIEWS_EXPORT ImageView : public View {
Alignment GetVerticalAlignment() const;
// Set / Get the tooltip text.
- void SetTooltipText(const string16& tooltip);
- string16 GetTooltipText() const;
+ void SetTooltipText(const base::string16& tooltip);
+ base::string16 GetTooltipText() const;
void set_interactive(bool interactive) { interactive_ = interactive; }
void SetFocusPainter(scoped_ptr<Painter> focus_painter);
// Overriden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE;
private:
void OnPaintImage(gfx::Canvas* canvas);
@@ -117,7 +117,7 @@ class VIEWS_EXPORT ImageView : public View {
Alignment vert_alignment_;
// The current tooltip text.
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
// A flag controlling hit test handling for interactivity.
bool interactive_;
diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc
index 7d4bc7e8470..648a0e660bc 100644
--- a/chromium/ui/views/controls/label.cc
+++ b/chromium/ui/views/controls/label.cc
@@ -14,27 +14,21 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/insets.h"
-#include "ui/gfx/shadow_value.h"
#include "ui/gfx/text_elider.h"
#include "ui/gfx/text_utils.h"
+#include "ui/gfx/utf16_indexing.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
namespace {
-// The padding for the focus border when rendering focused text.
-const int kFocusBorderPadding = 1;
const int kCachedSizeLimit = 10;
-
-gfx::FontList GetDefaultFontList() {
- return ui::ResourceBundle::GetSharedInstance().GetFontList(
- ui::ResourceBundle::BaseFont);
-}
+const base::char16 kPasswordReplacementChar = '*';
} // namespace
@@ -42,23 +36,20 @@ namespace views {
// static
const char Label::kViewClassName[] = "Label";
+const int Label::kFocusBorderPadding = 1;
Label::Label() {
- Init(string16(), GetDefaultFontList());
+ Init(base::string16(), gfx::FontList());
}
-Label::Label(const string16& text) {
- Init(text, GetDefaultFontList());
+Label::Label(const base::string16& text) {
+ Init(text, gfx::FontList());
}
-Label::Label(const string16& text, const gfx::FontList& font_list) {
+Label::Label(const base::string16& text, const gfx::FontList& font_list) {
Init(text, font_list);
}
-Label::Label(const string16& text, const gfx::Font& font) {
- Init(text, gfx::FontList(font));
-}
-
Label::~Label() {
}
@@ -69,18 +60,22 @@ void Label::SetFontList(const gfx::FontList& font_list) {
SchedulePaint();
}
-const gfx::Font& Label::font() const {
- return font_list_.GetPrimaryFont();
-}
-
-void Label::SetFont(const gfx::Font& font) {
- SetFontList(gfx::FontList(font));
+void Label::SetText(const base::string16& text) {
+ if (text != text_)
+ SetTextInternal(text);
}
-void Label::SetText(const string16& text) {
- if (text == text_)
- return;
+void Label::SetTextInternal(const base::string16& text) {
text_ = text;
+
+ if (is_obscured_) {
+ size_t obscured_text_length =
+ static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, text_.length()));
+ layout_text_.assign(obscured_text_length, kPasswordReplacementChar);
+ } else {
+ layout_text_ = text_;
+ }
+
ResetCachedSize();
PreferredSizeChanged();
SchedulePaint();
@@ -109,26 +104,10 @@ void Label::SetBackgroundColor(SkColor color) {
RecalculateColors();
}
-void Label::SetShadowColors(SkColor enabled_color, SkColor disabled_color) {
- enabled_shadow_color_ = enabled_color;
- disabled_shadow_color_ = disabled_color;
- has_shadow_ = true;
-}
-
-void Label::SetShadowOffset(int x, int y) {
- shadow_offset_.SetPoint(x, y);
-}
-
-void Label::ClearEmbellishing() {
- has_shadow_ = false;
-}
-
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;
}
@@ -138,6 +117,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;
@@ -148,7 +136,8 @@ void Label::SetLineHeight(int height) {
}
void Label::SetMultiLine(bool multi_line) {
- DCHECK(!multi_line || elide_behavior_ != ELIDE_IN_MIDDLE);
+ DCHECK(!multi_line || (elide_behavior_ == gfx::ELIDE_TAIL ||
+ elide_behavior_ == gfx::TRUNCATE));
if (multi_line != is_multi_line_) {
is_multi_line_ = multi_line;
ResetCachedSize();
@@ -157,6 +146,13 @@ void Label::SetMultiLine(bool multi_line) {
}
}
+void Label::SetObscured(bool obscured) {
+ if (obscured != is_obscured_) {
+ is_obscured_ = obscured;
+ SetTextInternal(text_);
+ }
+}
+
void Label::SetAllowCharacterBreak(bool allow_character_break) {
if (allow_character_break != allow_character_break_) {
allow_character_break_ = allow_character_break;
@@ -166,8 +162,9 @@ void Label::SetAllowCharacterBreak(bool allow_character_break) {
}
}
-void Label::SetElideBehavior(ElideBehavior elide_behavior) {
- DCHECK(elide_behavior != ELIDE_IN_MIDDLE || !is_multi_line_);
+void Label::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
+ DCHECK(!is_multi_line_ || (elide_behavior_ == gfx::ELIDE_TAIL ||
+ elide_behavior_ == gfx::TRUNCATE));
if (elide_behavior != elide_behavior_) {
elide_behavior_ = elide_behavior;
ResetCachedSize();
@@ -176,18 +173,18 @@ void Label::SetElideBehavior(ElideBehavior elide_behavior) {
}
}
-void Label::SetTooltipText(const string16& tooltip_text) {
+void Label::SetTooltipText(const base::string16& tooltip_text) {
tooltip_text_ = tooltip_text;
}
void Label::SizeToFit(int max_width) {
DCHECK(is_multi_line_);
- std::vector<string16> lines;
- base::SplitString(text_, '\n', &lines);
+ std::vector<base::string16> lines;
+ base::SplitString(layout_text(), '\n', &lines);
int label_width = 0;
- for (std::vector<string16>::const_iterator iter = lines.begin();
+ for (std::vector<base::string16>::const_iterator iter = lines.begin();
iter != lines.end(); ++iter) {
label_width = std::max(label_width, gfx::GetStringWidth(*iter, font_list_));
}
@@ -201,17 +198,9 @@ void Label::SizeToFit(int max_width) {
SizeToPreferredSize();
}
-void Label::SetHasFocusBorder(bool has_focus_border) {
- has_focus_border_ = has_focus_border;
- if (is_multi_line_) {
- ResetCachedSize();
- PreferredSizeChanged();
- }
-}
-
gfx::Insets Label::GetInsets() const {
gfx::Insets insets = View::GetInsets();
- if (focusable() || has_focus_border_) {
+ if (focusable()) {
insets += gfx::Insets(kFocusBorderPadding, kFocusBorderPadding,
kFocusBorderPadding, kFocusBorderPadding);
}
@@ -222,7 +211,7 @@ int Label::GetBaseline() const {
return GetInsets().top() + font_list_.GetBaseline();
}
-gfx::Size Label::GetPreferredSize() {
+gfx::Size Label::GetPreferredSize() const {
// Return a size of (0, 0) if the label is not visible and if the
// collapse_when_hidden_ flag is set.
// TODO(munjal): This logic probably belongs to the View class. But for now,
@@ -231,13 +220,27 @@ gfx::Size Label::GetPreferredSize() {
if (!visible() && collapse_when_hidden_)
return gfx::Size();
- gfx::Size prefsize(GetTextSize());
+ gfx::Size size(GetTextSize());
+ gfx::Insets insets = GetInsets();
+ size.Enlarge(insets.width(), insets.height());
+ return size;
+}
+
+gfx::Size Label::GetMinimumSize() const {
+ gfx::Size text_size(GetTextSize());
+ if ((!visible() && collapse_when_hidden_) || text_size.IsEmpty())
+ return gfx::Size();
+
+ gfx::Size size(gfx::GetStringWidth(base::string16(gfx::kEllipsisUTF16),
+ font_list_),
+ font_list_.GetHeight());
+ size.SetToMin(text_size); // The actual text may be shorter than an ellipsis.
gfx::Insets insets = GetInsets();
- prefsize.Enlarge(insets.width(), insets.height());
- return prefsize;
+ size.Enlarge(insets.width(), insets.height());
+ return size;
}
-int Label::GetHeightForWidth(int w) {
+int Label::GetHeightForWidth(int w) const {
if (!is_multi_line_)
return View::GetHeightForWidth(w);
@@ -253,7 +256,8 @@ int Label::GetHeightForWidth(int w) {
int h = font_list_.GetHeight();
const int flags = ComputeDrawStringFlags();
- gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, line_height_, flags);
+ gfx::Canvas::SizeStringInt(
+ layout_text(), font_list_, &w, &h, line_height_, flags);
cached_heights_[cached_heights_cursor_] = gfx::Size(cache_width, h);
cached_heights_cursor_ = (cached_heights_cursor_ + 1) % kCachedSizeLimit;
return h + GetInsets().height();
@@ -278,11 +282,12 @@ View* Label::GetTooltipHandlerForPoint(const gfx::Point& point) {
return this;
}
-bool Label::HitTestRect(const gfx::Rect& rect) const {
+bool Label::CanProcessEventsWithinSubtree() const {
+ // Send events to the parent view for handling.
return false;
}
-bool Label::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool Label::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const {
DCHECK(tooltip);
// If a tooltip has been explicitly set, use it.
@@ -293,30 +298,30 @@ bool Label::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
// Show the full text if the text does not fit.
if (ShouldShowDefaultTooltip()) {
- *tooltip = text_;
+ *tooltip = layout_text();
return true;
}
return false;
}
-void Label::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_STATICTEXT;
- state->state = ui::AccessibilityTypes::STATE_READONLY;
- state->name = text_;
+void Label::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_STATIC_TEXT;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
+ state->name = layout_text();
}
void Label::PaintText(gfx::Canvas* canvas,
- const string16& text,
+ const base::string16& text,
const gfx::Rect& text_bounds,
int flags) {
- gfx::ShadowValues shadows;
- if (has_shadow_)
- shadows.push_back(gfx::ShadowValue(shadow_offset_, 0,
- enabled() ? enabled_shadow_color_ : disabled_shadow_color_));
- canvas->DrawStringRectWithShadows(text, font_list_,
- enabled() ? actual_enabled_color_ : actual_disabled_color_,
- text_bounds, line_height_, flags, shadows);
+ SkColor color = enabled() ? actual_enabled_color_ : actual_disabled_color_;
+ if (elide_behavior_ == gfx::FADE_TAIL) {
+ canvas->DrawFadedString(text, font_list_, color, text_bounds, flags);
+ } else {
+ canvas->DrawStringRectWithShadows(text, font_list_, color, text_bounds,
+ line_height_, flags, shadows_);
+ }
if (HasFocus()) {
gfx::Rect focus_bounds = text_bounds;
@@ -339,8 +344,11 @@ gfx::Size Label::GetTextSize() const {
int flags = ComputeDrawStringFlags();
if (!is_multi_line_)
flags |= gfx::Canvas::NO_ELLIPSIS;
- gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, line_height_, flags);
+ gfx::Canvas::SizeStringInt(
+ layout_text(), font_list_, &w, &h, line_height_, flags);
text_size_.SetSize(w, h);
+ const gfx::Insets shadow_margin = -gfx::ShadowValue::GetMargin(shadows_);
+ text_size_.Enlarge(shadow_margin.width(), shadow_margin.height());
text_size_valid_ = true;
}
@@ -358,7 +366,7 @@ void Label::OnPaint(gfx::Canvas* canvas) {
// interfere with that.
OnPaintBorder(canvas);
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
int flags = 0;
CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
@@ -369,23 +377,20 @@ void Label::OnNativeThemeChanged(const ui::NativeTheme* theme) {
UpdateColorsFromTheme(theme);
}
-void Label::Init(const string16& text, const gfx::FontList& font_list) {
+void Label::Init(const base::string16& text, const gfx::FontList& font_list) {
font_list_ = font_list;
enabled_color_set_ = disabled_color_set_ = background_color_set_ = false;
+ subpixel_rendering_enabled_ = true;
auto_color_readability_ = true;
UpdateColorsFromTheme(ui::NativeTheme::instance());
horizontal_alignment_ = gfx::ALIGN_CENTER;
line_height_ = 0;
is_multi_line_ = false;
+ is_obscured_ = false;
allow_character_break_ = false;
- elide_behavior_ = ELIDE_AT_END;
+ elide_behavior_ = gfx::ELIDE_TAIL;
collapse_when_hidden_ = false;
- directionality_mode_ = USE_UI_DIRECTIONALITY;
- has_focus_border_ = false;
- enabled_shadow_color_ = 0;
- disabled_shadow_color_ = 0;
- shadow_offset_.SetPoint(1, 1);
- has_shadow_ = false;
+ directionality_mode_ = gfx::DIRECTIONALITY_FROM_UI;
cached_heights_.resize(kCachedSizeLimit);
ResetCachedSize();
@@ -404,52 +409,50 @@ 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 {
int flags = 0;
// We can't use subpixel rendering if the background is non-opaque.
- if (SkColorGetA(background_color_) != 0xFF)
+ if (SkColorGetA(background_color_) != 0xFF || !subpixel_rendering_enabled_)
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(text_);
+ base::i18n::GetFirstStrongCharacterDirection(layout_text());
if (direction == base::i18n::RIGHT_TO_LEFT)
flags |= gfx::Canvas::FORCE_RTL_DIRECTIONALITY;
else
flags |= gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
}
- switch (horizontal_alignment_) {
+ switch (GetHorizontalAlignment()) {
case gfx::ALIGN_LEFT:
flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
break;
@@ -459,6 +462,9 @@ int Label::ComputeDrawStringFlags() const {
case gfx::ALIGN_RIGHT:
flags |= gfx::Canvas::TEXT_ALIGN_RIGHT;
break;
+ default:
+ NOTREACHED();
+ break;
}
if (!is_multi_line_)
@@ -485,31 +491,25 @@ gfx::Rect Label::GetAvailableRect() const {
return bounds;
}
-void Label::CalculateDrawStringParams(string16* paint_text,
+void Label::CalculateDrawStringParams(base::string16* paint_text,
gfx::Rect* text_bounds,
int* flags) const {
DCHECK(paint_text && text_bounds && flags);
- // TODO(msw): Use ElideRectangleText to support eliding multi-line text. Once
- // this is done, we can set NO_ELLIPSIS unconditionally at the bottom.
- if (is_multi_line_ || (elide_behavior_ == NO_ELIDE)) {
- *paint_text = text_;
- } else if (elide_behavior_ == ELIDE_IN_MIDDLE) {
- *paint_text = gfx::ElideText(text_, font_list_, GetAvailableRect().width(),
- gfx::ELIDE_IN_MIDDLE);
- } else if (elide_behavior_ == ELIDE_AT_END) {
- *paint_text = gfx::ElideText(text_, font_list_, GetAvailableRect().width(),
- gfx::ELIDE_AT_END);
+ const bool forbid_ellipsis = elide_behavior_ == gfx::TRUNCATE ||
+ elide_behavior_ == gfx::FADE_TAIL;
+ if (is_multi_line_ || forbid_ellipsis) {
+ *paint_text = layout_text();
} else {
- DCHECK_EQ(ELIDE_AS_EMAIL, elide_behavior_);
- *paint_text = gfx::ElideEmail(text_, font_list_,
- GetAvailableRect().width());
+ *paint_text = gfx::ElideText(layout_text(), font_list_,
+ GetAvailableRect().width(), elide_behavior_);
}
*text_bounds = GetTextBounds();
*flags = ComputeDrawStringFlags();
- if (!is_multi_line_ || (elide_behavior_ == NO_ELIDE))
- *flags |= gfx::Canvas::NO_ELLIPSIS;
+ // TODO(msw): Elide multi-line text with ElideRectangleText instead.
+ if (!is_multi_line_ || forbid_ellipsis)
+ *flags |= gfx::Canvas::NO_ELLIPSIS;
}
void Label::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
@@ -536,8 +536,9 @@ void Label::ResetCachedSize() {
}
bool Label::ShouldShowDefaultTooltip() const {
- return !is_multi_line_ &&
- gfx::GetStringWidth(text_, font_list_) > GetAvailableRect().width();
+ return !is_multi_line_ && !is_obscured_ &&
+ gfx::GetStringWidth(layout_text(), font_list_) >
+ GetAvailableRect().width();
}
} // namespace views
diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h
index 40534ff654f..f146b18d4af 100644
--- a/chromium/ui/views/controls/label.h
+++ b/chromium/ui/views/controls/label.h
@@ -13,61 +13,33 @@
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/font_list.h"
+#include "ui/gfx/shadow_value.h"
#include "ui/gfx/text_constants.h"
#include "ui/views/view.h"
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:
// Internal class name.
static const char kViewClassName[];
- // 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
- };
-
- enum ElideBehavior {
- NO_ELIDE, // Do not elide the label text; truncate as needed.
- ELIDE_IN_MIDDLE, // Add ellipsis in the middle of the string as needed.
- ELIDE_AT_END, // Add ellipsis at the end of the string as needed.
- ELIDE_AS_EMAIL, // Elide while retaining username/domain chars as needed.
- };
+ // The padding for the focus border when rendering focused text.
+ static const int kFocusBorderPadding;
Label();
- explicit Label(const string16& text);
- Label(const string16& text, const gfx::FontList& font_list);
- Label(const string16& text, const gfx::Font& font); // OBSOLETE
+ explicit Label(const base::string16& text);
+ Label(const base::string16& text, const gfx::FontList& font_list);
virtual ~Label();
// Gets or sets the fonts used by this label.
const gfx::FontList& font_list() const { return font_list_; }
virtual void SetFontList(const gfx::FontList& font_list);
- // Obsolete gfx::Font version. Should use gfx::FontList version instead.
- const gfx::Font& font() const; // OBSOLETE
- virtual void SetFont(const gfx::Font& font); // OBSOLETE
// Get or set the label text.
- const string16& text() const { return text_; }
- void SetText(const string16& text);
+ const base::string16& text() const { return text_; }
+ virtual void SetText(const base::string16& text);
// Enables or disables auto-color-readability (enabled by default). If this
// is enabled, then calls to set any foreground or background color will
@@ -87,37 +59,30 @@ class VIEWS_EXPORT Label : public View {
void SetBackgroundColor(SkColor color);
SkColor background_color() const { return background_color_; }
- // Enables a drop shadow underneath the text.
- void SetShadowColors(SkColor enabled_color, SkColor disabled_color);
-
- // Sets the drop shadow's offset from the text.
- void SetShadowOffset(int x, int y);
+ // Set drop shadows underneath the text.
+ void set_shadows(const gfx::ShadowValues& shadows) {
+ shadows_ = shadows;
+ text_size_valid_ = false;
+ }
+ const gfx::ShadowValues& shadows() const { return shadows_; }
- // Disables shadows.
- void ClearEmbellishing();
+ // Sets whether subpixel rendering is used; the default is true, but this
+ // feature also requires an opaque background color.
+ void set_subpixel_rendering_enabled(bool subpixel_rendering_enabled) {
+ subpixel_rendering_enabled_ = subpixel_rendering_enabled;
+ }
- // 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_;
}
@@ -131,20 +96,27 @@ class VIEWS_EXPORT Label : public View {
bool is_multi_line() const { return is_multi_line_; }
void SetMultiLine(bool multi_line);
+ // Get or set if the label text should be obscured before rendering (e.g.
+ // should "Password!" display as "*********"); default is false.
+ bool is_obscured() const { return is_obscured_; }
+ void SetObscured(bool obscured);
+
+ // Get the text as displayed to the user, respecting the 'obscured' flag.
+ const base::string16& layout_text() const { return layout_text_; }
+
// Sets whether the label text can be split on words.
// Default is false. This only works when is_multi_line is true.
void SetAllowCharacterBreak(bool allow_character_break);
- // Sets whether the label text should be elided in the middle or end (if
- // necessary). The default is to elide at the end.
- // NOTE: Eliding in the middle is not supported for multi-line strings.
- void SetElideBehavior(ElideBehavior elide_behavior);
+ // Sets the eliding or fading behavior, applied as necessary. The default is
+ // to elide at the end. Eliding is not well supported for multi-line labels.
+ void SetElideBehavior(gfx::ElideBehavior elide_behavior);
// Sets the tooltip text. Default behavior for a label (single-line) is to
// show the full text if it is wider than its bounds. Calling this overrides
// the default behavior and lets you set a custom tooltip. To revert to
// default behavior, call this with an empty string.
- void SetTooltipText(const string16& tooltip_text);
+ void SetTooltipText(const base::string16& tooltip_text);
// Resizes the label so its width is set to the width of the longest line and
// its height deduced accordingly.
@@ -160,33 +132,33 @@ class VIEWS_EXPORT Label : public View {
void set_collapse_when_hidden(bool value) { collapse_when_hidden_ = value; }
bool collapse_when_hidden() const { return collapse_when_hidden_; }
- void SetHasFocusBorder(bool has_focus_border);
-
- // Overridden from View:
+ // View:
virtual gfx::Insets GetInsets() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
// Overridden to compute the size required to display this label.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ // Returns the width of an ellipsis if the label is non-empty, or 0 otherwise.
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
// Returns the height necessary to display this label with the provided width.
// This method is used to layout multi-line labels. It is equivalent to
// GetPreferredSize().height() if the receiver is not multi-line.
- virtual int GetHeightForWidth(int w) OVERRIDE;
+ virtual int GetHeightForWidth(int w) const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual View* GetTooltipHandlerForPoint(const gfx::Point& point) OVERRIDE;
- virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// Gets the tooltip text for labels that are wider than their bounds, except
// when the label is multiline, in which case it just returns false (no
// tooltip). If a custom tooltip has been specified with SetTooltipText()
// it is returned instead.
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
protected:
// Called by Paint to paint the text. Override this to change how
// text is painted.
virtual void PaintText(gfx::Canvas* canvas,
- const string16& text,
+ const base::string16& text,
const gfx::Rect& text_bounds,
int flags);
@@ -207,12 +179,14 @@ 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);
- void Init(const string16& text, const gfx::FontList& font_list);
+ // Sets both |text_| and |layout_text_| to appropriate values, taking
+ // the label's 'obscured' status into account.
+ void SetTextInternal(const base::string16& text);
+
+ void Init(const base::string16& text, const gfx::FontList& font_list);
void RecalculateColors();
@@ -224,7 +198,7 @@ class VIEWS_EXPORT Label : public View {
gfx::Rect GetAvailableRect() const;
// Returns parameters to be used for the DrawString call.
- void CalculateDrawStringParams(string16* paint_text,
+ void CalculateDrawStringParams(base::string16* paint_text,
gfx::Rect* text_bounds,
int* flags) const;
@@ -237,7 +211,8 @@ class VIEWS_EXPORT Label : public View {
bool ShouldShowDefaultTooltip() const;
- string16 text_;
+ base::string16 text_;
+ base::string16 layout_text_;
gfx::FontList font_list_;
SkColor requested_enabled_color_;
SkColor actual_enabled_color_;
@@ -250,39 +225,27 @@ class VIEWS_EXPORT Label : public View {
bool disabled_color_set_;
bool background_color_set_;
+ bool subpixel_rendering_enabled_;
bool auto_color_readability_;
mutable gfx::Size text_size_;
mutable bool text_size_valid_;
int line_height_;
bool is_multi_line_;
+ bool is_obscured_;
bool allow_character_break_;
- ElideBehavior elide_behavior_;
+ gfx::ElideBehavior elide_behavior_;
gfx::HorizontalAlignment horizontal_alignment_;
- string16 tooltip_text_;
+ 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_;
- // When embedded in a larger control that is focusable, setting this flag
- // allows this view to reserve space for a focus border that it otherwise
- // might not have because it is not itself focusable.
- bool has_focus_border_;
-
- // Colors for shadow.
- SkColor enabled_shadow_color_;
- SkColor disabled_shadow_color_;
-
- // Space between text and shadow.
- gfx::Point shadow_offset_;
-
- // Should a shadow be drawn behind the text?
- bool has_shadow_;
+ // 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_;
+ gfx::ShadowValues shadows_;
// The cached heights to avoid recalculation in GetHeightForWidth().
- std::vector<gfx::Size> cached_heights_;
- int cached_heights_cursor_;
+ mutable std::vector<gfx::Size> cached_heights_;
+ mutable int cached_heights_cursor_;
DISALLOW_COPY_AND_ASSIGN(Label);
};
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index e2a37c3a167..8b16d0f6844 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -7,16 +7,25 @@
#include "base/i18n/rtl.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/views/border.h"
+using base::ASCIIToUTF16;
+
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");
@@ -39,7 +48,7 @@ TEST(LabelTest, FontPropertyArial) {
TEST(LabelTest, TextProperty) {
Label label;
- string16 test_text(ASCIIToUTF16("A random string."));
+ base::string16 test_text(ASCIIToUTF16("A random string."));
label.SetText(test_text);
EXPECT_EQ(test_text, label.text());
}
@@ -53,38 +62,45 @@ TEST(LabelTest, ColorProperty) {
}
TEST(LabelTest, AlignmentProperty) {
- Label label;
- bool reverse_alignment = base::i18n::IsRTL();
+ const bool was_rtl = 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());
+ 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());
+ }
+ }
- // 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());
+ 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) {
@@ -96,24 +112,59 @@ TEST(LabelTest, MultiLineProperty) {
EXPECT_FALSE(label.is_multi_line());
}
-TEST(LabelTest, TooltipProperty) {
+TEST(LabelTest, ObscuredProperty) {
Label label;
- string16 test_text(ASCIIToUTF16("My cool string."));
+ base::string16 test_text(ASCIIToUTF16("Password!"));
label.SetText(test_text);
- string16 tooltip;
+ // Should be false by default...
+ EXPECT_FALSE(label.is_obscured());
+ EXPECT_EQ(test_text, label.layout_text());
+ EXPECT_EQ(test_text, label.text());
+
+ label.SetObscured(true);
+ EXPECT_TRUE(label.is_obscured());
+ EXPECT_EQ(ASCIIToUTF16("*********"), label.layout_text());
+ EXPECT_EQ(test_text, label.text());
+
+ label.SetText(test_text + test_text);
+ EXPECT_EQ(ASCIIToUTF16("******************"), label.layout_text());
+ EXPECT_EQ(test_text + test_text, label.text());
+
+ label.SetObscured(false);
+ EXPECT_FALSE(label.is_obscured());
+ EXPECT_EQ(test_text + test_text, label.layout_text());
+ EXPECT_EQ(test_text + test_text, label.text());
+}
+
+TEST(LabelTest, ObscuredSurrogatePair) {
+ // 'MUSICAL SYMBOL G CLEF': represented in UTF-16 as two characters
+ // forming the surrogate pair 0x0001D11E.
+ Label label;
+ base::string16 test_text = base::UTF8ToUTF16("\xF0\x9D\x84\x9E");
+ label.SetText(test_text);
+
+ label.SetObscured(true);
+ EXPECT_EQ(ASCIIToUTF16("*"), label.layout_text());
+ EXPECT_EQ(test_text, label.text());
+}
+
+TEST(LabelTest, TooltipProperty) {
+ Label label;
+ label.SetText(ASCIIToUTF16("My cool string."));
+
+ base::string16 tooltip;
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
- EXPECT_EQ(test_text, tooltip);
+ EXPECT_EQ(label.text(), tooltip);
- string16 tooltip_text(ASCIIToUTF16("The tooltip!"));
+ base::string16 tooltip_text(ASCIIToUTF16("The tooltip!"));
label.SetTooltipText(tooltip_text);
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
EXPECT_EQ(tooltip_text, tooltip);
- string16 empty_text;
- label.SetTooltipText(empty_text);
+ label.SetTooltipText(base::string16());
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
- EXPECT_EQ(test_text, tooltip);
+ EXPECT_EQ(label.text(), tooltip);
// Make the label big enough to hold the text
// and expect there to be no tooltip.
@@ -125,13 +176,21 @@ TEST(LabelTest, TooltipProperty) {
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
EXPECT_EQ(tooltip_text, tooltip);
// Clear out the tooltip.
- label.SetTooltipText(empty_text);
+ label.SetTooltipText(base::string16());
// Shrink the bounds and the tooltip should come back.
label.SetBounds(0, 0, 1, 1);
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
- // Make the label multiline and there is no tooltip again.
+ // Make the label obscured and there is no tooltip.
+ label.SetObscured(true);
+ EXPECT_FALSE(label.GetTooltipText(gfx::Point(), &tooltip));
+
+ // Obscuring the text shouldn't permanently clobber the tooltip.
+ label.SetObscured(false);
+ EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
+
+ // Make the label multiline and there is no tooltip.
label.SetMultiLine(true);
EXPECT_FALSE(label.GetTooltipText(gfx::Point(), &tooltip));
@@ -140,25 +199,23 @@ TEST(LabelTest, TooltipProperty) {
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
EXPECT_EQ(tooltip_text, tooltip);
// Clear out the tooltip.
- label.SetTooltipText(empty_text);
+ label.SetTooltipText(base::string16());
}
TEST(LabelTest, Accessibility) {
Label label;
- string16 test_text(ASCIIToUTF16("My special text."));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("My special text."));
- ui::AccessibleViewState state;
+ ui::AXViewState state;
label.GetAccessibleState(&state);
- EXPECT_EQ(ui::AccessibilityTypes::ROLE_STATICTEXT, state.role);
- EXPECT_EQ(test_text, state.name);
- EXPECT_TRUE(ui::AccessibilityTypes::STATE_READONLY & state.state);
+ EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, state.role);
+ EXPECT_EQ(label.text(), state.name);
+ EXPECT_TRUE(state.HasStateFlag(ui::AX_STATE_READ_ONLY));
}
TEST(LabelTest, SingleLineSizing) {
Label label;
- string16 test_text(ASCIIToUTF16("A not so random string in one line."));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("A not so random string in one line."));
// GetPreferredSize
gfx::Size required_size = label.GetPreferredSize();
@@ -167,10 +224,8 @@ TEST(LabelTest, SingleLineSizing) {
// Test everything with borders.
gfx::Insets border(10, 20, 30, 40);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
// GetPreferredSize and borders.
label.SetBounds(0, 0, 0, 0);
@@ -183,28 +238,23 @@ TEST(LabelTest, SingleLineSizing) {
TEST(LabelTest, MultilineSmallAvailableWidthSizing) {
Label label;
- string16 test_text(ASCIIToUTF16("Too Wide."));
-
label.SetMultiLine(true);
label.SetAllowCharacterBreak(true);
- label.SetElideBehavior(Label::ELIDE_AT_END);
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Too Wide."));
// Check that Label can be laid out at a variety of small sizes,
// splitting the words into up to one character per line if necessary.
// Incorrect word splitting may cause infinite loops in text layout.
gfx::Size required_size = label.GetPreferredSize();
- for (int i = 1; i < required_size.width(); ++i) {
+ for (int i = 1; i < required_size.width(); ++i)
EXPECT_GT(label.GetHeightForWidth(i), 0);
- }
}
TEST(LabelTest, MultiLineSizing) {
Label label;
label.SetFocusable(false);
- string16 test_text(
+ label.SetText(
ASCIIToUTF16("A random string\nwith multiple lines\nand returns!"));
- label.SetText(test_text);
label.SetMultiLine(true);
// GetPreferredSize
@@ -248,10 +298,8 @@ TEST(LabelTest, MultiLineSizing) {
// Test everything with borders.
gfx::Insets border(10, 20, 30, 40);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
// SizeToFit and borders.
label.SizeToFit(0);
@@ -283,37 +331,23 @@ 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.
- string16 test_text(WideToUTF16(L" \x5d0\x5d1\x5d2 abc"));
- label.SetText(test_text);
- 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());
-
- string16 paint_text;
- gfx::Rect text_bounds;
- int flags;
+ label.SetText(base::WideToUTF16(L" \x5d0\x5d1\x5d2 abc"));
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
EXPECT_EQ(gfx::Canvas::FORCE_RTL_DIRECTIONALITY,
flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY));
// Test text starts with LTR character.
- test_text = (WideToUTF16(L"ltr \x5d0\x5d1\x5d2 abc"));
- label.SetText(test_text);
- required_size = label.GetPreferredSize();
- label.SetBounds(0,
- 0,
- required_size.width() + extra.width(),
- required_size.height() + extra.height());
-
+ label.SetText(base::WideToUTF16(L"ltr \x5d0\x5d1\x5d2 abc"));
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
EXPECT_EQ(gfx::Canvas::FORCE_LTR_DIRECTIONALITY,
flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY |
@@ -323,28 +357,23 @@ TEST(LabelTest, AutoDetectDirectionality) {
TEST(LabelTest, DrawSingleLineString) {
Label label;
label.SetFocusable(false);
+ // Force a directionality to simplify alignment value testing.
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FORCE_LTR);
- // 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);
-
- string16 test_text(ASCIIToUTF16("Here's a string with no returns."));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Here's a string with no returns."));
gfx::Size required_size(label.GetPreferredSize());
gfx::Size extra(22, 8);
- label.SetBounds(0,
- 0,
- required_size.width() + extra.width(),
+ label.SetBounds(0, 0, required_size.width() + extra.width(),
required_size.height() + extra.height());
// Do some basic verifications for all three alignments.
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
// Centered text.
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be centered horizontally and vertically.
EXPECT_EQ(extra.width() / 2, text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -360,7 +389,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be left aligned horizontally and centered vertically.
EXPECT_EQ(0, text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -376,7 +405,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be right aligned horizontally and centered vertically.
EXPECT_EQ(extra.width(), text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -389,19 +418,15 @@ TEST(LabelTest, DrawSingleLineString) {
// Test single line drawing with a border.
gfx::Insets border(39, 34, 8, 96);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
gfx::Size required_size_with_border(label.GetPreferredSize());
EXPECT_EQ(required_size.width() + border.width(),
required_size_with_border.width());
EXPECT_EQ(required_size.height() + border.height(),
required_size_with_border.height());
- label.SetBounds(0,
- 0,
- required_size_with_border.width() + extra.width(),
+ label.SetBounds(0, 0, required_size_with_border.width() + extra.width(),
required_size_with_border.height() + extra.height());
// Centered text with border.
@@ -409,7 +434,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be centered horizontally and vertically within the border.
EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -425,7 +450,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be left aligned horizontally and centered vertically.
EXPECT_EQ(border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -441,7 +466,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be right aligned horizontally and centered vertically.
EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -453,33 +478,29 @@ 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);
+ // 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);
- // 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);
-
- string16 test_text(ASCIIToUTF16("Another string\nwith returns\n\n!"));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Another string\nwith returns\n\n!"));
label.SetMultiLine(true);
label.SizeToFit(0);
gfx::Size extra(50, 10);
- label.SetBounds(label.x(),
- label.y(),
+ label.SetBounds(label.x(), label.y(),
label.width() + extra.width(),
label.height() + extra.height());
// Do some basic verifications for all three alignments.
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width() / 2, text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
@@ -487,18 +508,17 @@ TEST(LabelTest, DrawMultiLineString) {
int expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_CENTER |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
gfx::Rect center_bounds(text_bounds);
label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(0, text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
@@ -506,17 +526,16 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_LEFT |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width(), text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
@@ -524,21 +543,17 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_RIGHT |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
// Test multiline drawing with a border.
gfx::Insets border(19, 92, 23, 2);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
label.SizeToFit(0);
- label.SetBounds(label.x(),
- label.y(),
+ label.SetBounds(label.x(), label.y(),
label.width() + extra.width(),
label.height() + extra.height());
@@ -546,7 +561,7 @@ TEST(LabelTest, DrawMultiLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
@@ -554,17 +569,16 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_CENTER |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
@@ -572,17 +586,16 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_LEFT |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width() + border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
@@ -590,11 +603,10 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_RIGHT |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
}
TEST(LabelTest, DrawSingleLineStringInRTL) {
@@ -604,23 +616,20 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
std::string locale = l10n_util::GetApplicationLocale("");
base::i18n::SetICUDefaultLocale("he");
- string16 test_text(ASCIIToUTF16("Here's a string with no returns."));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Here's a string with no returns."));
gfx::Size required_size(label.GetPreferredSize());
gfx::Size extra(22, 8);
- label.SetBounds(0,
- 0,
- required_size.width() + extra.width(),
+ label.SetBounds(0, 0, required_size.width() + extra.width(),
required_size.height() + extra.height());
// Do some basic verifications for all three alignments.
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
// Centered text.
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be centered horizontally and vertically.
EXPECT_EQ(extra.width() / 2, text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -636,7 +645,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be right aligned horizontally and centered vertically.
EXPECT_EQ(extra.width(), text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -652,7 +661,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be left aligned horizontally and centered vertically.
EXPECT_EQ(0, text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -666,19 +675,15 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
// Test single line drawing with a border.
gfx::Insets border(39, 34, 8, 96);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
gfx::Size required_size_with_border(label.GetPreferredSize());
EXPECT_EQ(required_size.width() + border.width(),
required_size_with_border.width());
EXPECT_EQ(required_size.height() + border.height(),
required_size_with_border.height());
- label.SetBounds(0,
- 0,
- required_size_with_border.width() + extra.width(),
+ label.SetBounds(0, 0, required_size_with_border.width() + extra.width(),
required_size_with_border.height() + extra.height());
// Centered text with border.
@@ -686,7 +691,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be centered horizontally and vertically within the border.
EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -702,7 +707,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be right aligned horizontally and centered vertically.
EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -718,7 +723,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be left aligned horizontally and centered vertically.
EXPECT_EQ(border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -744,34 +749,28 @@ TEST(LabelTest, DrawMultiLineStringInRTL) {
std::string locale = l10n_util::GetApplicationLocale("");
base::i18n::SetICUDefaultLocale("he");
- string16 test_text(ASCIIToUTF16("Another string\nwith returns\n\n!"));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Another string\nwith returns\n\n!"));
label.SetMultiLine(true);
label.SizeToFit(0);
gfx::Size extra(50, 10);
- label.SetBounds(label.x(),
- label.y(),
+ label.SetBounds(label.x(), label.y(),
label.width() + extra.width(),
label.height() + extra.height());
// Do some basic verifications for all three alignments.
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width() / 2, text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
EXPECT_GT(text_bounds.height(), kMinTextDimension);
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_CENTER, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_CENTER |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_CENTER & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
gfx::Rect center_bounds(text_bounds);
@@ -779,49 +778,38 @@ TEST(LabelTest, DrawMultiLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width(), text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
EXPECT_GT(text_bounds.height(), kMinTextDimension);
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_RIGHT, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_RIGHT |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_RIGHT & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(0, text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
EXPECT_GT(text_bounds.height(), kMinTextDimension);
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_LEFT, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_LEFT |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_LEFT & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
// Test multiline drawing with a border.
gfx::Insets border(19, 92, 23, 2);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
label.SizeToFit(0);
- label.SetBounds(label.x(),
- label.y(),
+ label.SetBounds(label.x(), label.y(),
label.width() + extra.width(),
label.height() + extra.height());
@@ -829,75 +817,64 @@ TEST(LabelTest, DrawMultiLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
EXPECT_EQ(center_bounds.height(), text_bounds.height());
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_CENTER, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_CENTER |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_CENTER & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
EXPECT_EQ(center_bounds.height(), text_bounds.height());
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_RIGHT, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_RIGHT |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_RIGHT & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
EXPECT_EQ(center_bounds.height(), text_bounds.height());
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_LEFT, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_LEFT |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_LEFT & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
// Reset Locale
base::i18n::SetICUDefaultLocale(locale);
}
-// Check that we disable subpixel rendering when a transparent background is
-// being used.
+// Ensure the subpixel rendering flag and background color alpha are respected.
TEST(LabelTest, DisableSubpixelRendering) {
Label label;
label.SetBackgroundColor(SK_ColorWHITE);
- EXPECT_EQ(
- 0, label.ComputeDrawStringFlags() & gfx::Canvas::NO_SUBPIXEL_RENDERING);
-
+ const int flag = gfx::Canvas::NO_SUBPIXEL_RENDERING;
+ EXPECT_EQ(0, label.ComputeDrawStringFlags() & flag);
+ label.set_subpixel_rendering_enabled(false);
+ EXPECT_EQ(flag, label.ComputeDrawStringFlags() & flag);
+ label.set_subpixel_rendering_enabled(true);
+ EXPECT_EQ(0, label.ComputeDrawStringFlags() & flag);
+ // Text cannot be drawn with subpixel rendering on transparent backgrounds.
label.SetBackgroundColor(SkColorSetARGB(64, 255, 255, 255));
- EXPECT_EQ(
- gfx::Canvas::NO_SUBPIXEL_RENDERING,
- label.ComputeDrawStringFlags() & gfx::Canvas::NO_SUBPIXEL_RENDERING);
+ EXPECT_EQ(flag, label.ComputeDrawStringFlags() & flag);
}
// Check that labels support GetTooltipHandlerForPoint.
diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc
index d02a0b89c73..d8a08a40c92 100644
--- a/chromium/ui/views/controls/link.cc
+++ b/chromium/ui/views/controls/link.cc
@@ -8,27 +8,25 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/controls/link_listener.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+#include "ui/views/native_cursor.h"
namespace views {
const char Link::kViewClassName[] = "Link";
-Link::Link() : Label(string16()) {
+Link::Link() : Label(base::string16()) {
Init();
}
-Link::Link(const string16& title) : Label(title) {
+Link::Link(const base::string16& title) : Label(title) {
Init();
}
@@ -43,11 +41,6 @@ SkColor Link::GetDefaultEnabledColor() {
#endif
}
-void Link::OnEnabledChanged() {
- RecalculateFont();
- View::OnEnabledChanged();
-}
-
const char* Link::GetClassName() const {
return kViewClassName;
}
@@ -55,37 +48,13 @@ const char* Link::GetClassName() const {
gfx::NativeCursor Link::GetCursor(const ui::MouseEvent& event) {
if (!enabled())
return gfx::kNullCursor;
-#if defined(USE_AURA)
- return ui::kCursorHand;
-#elif defined(OS_WIN)
- static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_HAND);
- return g_hand_cursor;
-#endif
-}
-
-void Link::OnPaint(gfx::Canvas* canvas) {
- Label::OnPaint(canvas);
-
- if (HasFocus())
- canvas->DrawFocusRect(GetLocalBounds());
-}
-
-void Link::OnFocus() {
- Label::OnFocus();
- // We render differently focused.
- SchedulePaint();
-}
-
-void Link::OnBlur() {
- Label::OnBlur();
- // We render differently focused.
- SchedulePaint();
+ return GetNativeHandCursor();
}
-bool Link::HitTestRect(const gfx::Rect& rect) const {
- // We need to allow clicks on the link. So we override the implementation in
- // Label and use the default implementation of View.
- return View::HitTestRect(rect);
+bool Link::CanProcessEventsWithinSubtree() const {
+ // Links need to be able to accept events (e.g., clicking) even though
+ // in general Labels do not.
+ return View::CanProcessEventsWithinSubtree();
}
bool Link::OnMousePressed(const ui::MouseEvent& event) {
@@ -139,17 +108,6 @@ bool Link::OnKeyPressed(const ui::KeyEvent& event) {
return true;
}
-bool Link::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
- // Make sure we don't process space or enter as accelerators.
- return (event.key_code() == ui::VKEY_SPACE) ||
- (event.key_code() == ui::VKEY_RETURN);
-}
-
-void Link::GetAccessibleState(ui::AccessibleViewState* state) {
- Label::GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_LINK;
-}
-
void Link::OnGestureEvent(ui::GestureEvent* event) {
if (!enabled())
return;
@@ -167,9 +125,45 @@ void Link::OnGestureEvent(ui::GestureEvent* event) {
event->SetHandled();
}
-void Link::SetFont(const gfx::Font& font) {
- Label::SetFont(font);
+bool Link::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
+ // Make sure we don't process space or enter as accelerators.
+ return (event.key_code() == ui::VKEY_SPACE) ||
+ (event.key_code() == ui::VKEY_RETURN);
+}
+
+void Link::GetAccessibleState(ui::AXViewState* state) {
+ Label::GetAccessibleState(state);
+ state->role = ui::AX_ROLE_LINK;
+}
+
+void Link::OnEnabledChanged() {
RecalculateFont();
+ View::OnEnabledChanged();
+}
+
+void Link::OnFocus() {
+ Label::OnFocus();
+ // We render differently focused.
+ SchedulePaint();
+}
+
+void Link::OnBlur() {
+ Label::OnBlur();
+ // We render differently focused.
+ SchedulePaint();
+}
+
+void Link::SetFontList(const gfx::FontList& font_list) {
+ Label::SetFontList(font_list);
+ RecalculateFont();
+}
+
+void Link::SetText(const base::string16& text) {
+ Label::SetText(text);
+ // Disable focusability for empty links. Otherwise Label::GetInsets() will
+ // give them an unconditional 1-px. inset on every side to allow for a focus
+ // border, when in this case we probably wanted zero width.
+ SetFocusable(!text.empty());
}
void Link::SetEnabledColor(SkColor color) {
@@ -205,7 +199,12 @@ void Link::Init() {
SetPressedColor(SK_ColorRED);
#endif
RecalculateFont();
- SetFocusable(true);
+
+ // Label::Init() calls SetText(), but if that's being called from Label(), our
+ // SetText() override will not be reached (because the constructed class is
+ // only a Label at the moment, not yet a Link). So so the set_focusable()
+ // call explicitly here.
+ SetFocusable(!text().empty());
}
void Link::SetPressed(bool pressed) {
@@ -220,11 +219,11 @@ void Link::SetPressed(bool pressed) {
void Link::RecalculateFont() {
// Underline the link iff it is enabled and |underline_| is true.
- const int style = font().GetStyle();
+ const int style = font_list().GetFontStyle();
const int intended_style = (enabled() && underline_) ?
(style | gfx::Font::UNDERLINE) : (style & ~gfx::Font::UNDERLINE);
if (style != intended_style)
- Label::SetFont(font().DeriveFont(0, intended_style));
+ Label::SetFontList(font_list().DeriveWithStyle(intended_style));
}
} // namespace views
diff --git a/chromium/ui/views/controls/link.h b/chromium/ui/views/controls/link.h
index f6a876de863..4d5cf6b7afa 100644
--- a/chromium/ui/views/controls/link.h
+++ b/chromium/ui/views/controls/link.h
@@ -25,7 +25,7 @@ class LinkListener;
class VIEWS_EXPORT Link : public Label {
public:
Link();
- explicit Link(const string16& title);
+ explicit Link(const base::string16& title);
virtual ~Link();
static SkColor GetDefaultEnabledColor();
@@ -33,30 +33,26 @@ class VIEWS_EXPORT Link : public Label {
const LinkListener* listener() { return listener_; }
void set_listener(LinkListener* listener) { listener_ = listener; }
- // Overridden from View:
- virtual void OnEnabledChanged() OVERRIDE;
+ // Label:
virtual const char* GetClassName() const OVERRIDE;
virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnFocus() OVERRIDE;
- virtual void OnBlur() OVERRIDE;
- virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseCaptureLost() OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual bool SkipDefaultKeyEventProcessing(
const ui::KeyEvent& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
-
- // Overridden from ui::EventHandler:
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
-
- // Overridden from Label:
- virtual void SetFont(const gfx::Font& font) OVERRIDE;
-
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual void OnEnabledChanged() OVERRIDE;
+ virtual void OnFocus() OVERRIDE;
+ virtual void OnBlur() OVERRIDE;
+ virtual void SetFontList(const gfx::FontList& font_list) OVERRIDE;
+ virtual void SetText(const base::string16& text) OVERRIDE;
virtual void SetEnabledColor(SkColor color) OVERRIDE;
+
void SetPressedColor(SkColor color);
void SetUnderline(bool underline);
diff --git a/chromium/ui/views/controls/menu/display_change_listener_mac.cc b/chromium/ui/views/controls/menu/display_change_listener_mac.cc
new file mode 100644
index 00000000000..d9dfeda5cfd
--- /dev/null
+++ b/chromium/ui/views/controls/menu/display_change_listener_mac.cc
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_runner.h"
+
+namespace views {
+namespace internal {
+
+// static
+DisplayChangeListener* DisplayChangeListener::Create(Widget*, MenuRunner*) {
+ return NULL;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu.cc b/chromium/ui/views/controls/menu/menu.cc
index 597dba4419f..0cffae8f50e 100644
--- a/chromium/ui/views/controls/menu/menu.cc
+++ b/chromium/ui/views/controls/menu/menu.cc
@@ -17,8 +17,8 @@ bool Menu::Delegate::IsItemDefault(int id) const {
return false;
}
-string16 Menu::Delegate::GetLabel(int id) const {
- return string16();
+base::string16 Menu::Delegate::GetLabel(int id) const {
+ return base::string16();
}
bool Menu::Delegate::GetAcceleratorInfo(int id, ui::Accelerator* accel) {
@@ -49,7 +49,7 @@ bool Menu::Delegate::IsCommandEnabled(int id) const {
return true;
}
-bool Menu::Delegate::GetContextualLabel(int id, string16* out) const {
+bool Menu::Delegate::GetContextualLabel(int id, base::string16* out) const {
return false;
}
@@ -76,14 +76,14 @@ Menu::~Menu() {
}
void Menu::AppendMenuItem(int item_id,
- const string16& label,
+ const base::string16& label,
MenuItemType type) {
AddMenuItem(-1, item_id, label, type);
}
void Menu::AddMenuItem(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
MenuItemType type) {
if (type == SEPARATOR)
AddSeparator(index);
@@ -91,27 +91,27 @@ void Menu::AddMenuItem(int index,
AddMenuItemInternal(index, item_id, label, gfx::ImageSkia(), type);
}
-Menu* Menu::AppendSubMenu(int item_id, const string16& label) {
+Menu* Menu::AppendSubMenu(int item_id, const base::string16& label) {
return AddSubMenu(-1, item_id, label);
}
-Menu* Menu::AddSubMenu(int index, int item_id, const string16& label) {
+Menu* Menu::AddSubMenu(int index, int item_id, const base::string16& label) {
return AddSubMenuWithIcon(index, item_id, label, gfx::ImageSkia());
}
Menu* Menu::AppendSubMenuWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
return AddSubMenuWithIcon(-1, item_id, label, icon);
}
-void Menu::AppendMenuItemWithLabel(int item_id, const string16& label) {
+void Menu::AppendMenuItemWithLabel(int item_id, const base::string16& label) {
AddMenuItemWithLabel(-1, item_id, label);
}
void Menu::AddMenuItemWithLabel(int index,
int item_id,
- const string16& label) {
+ const base::string16& label) {
AddMenuItem(index, item_id, label, Menu::NORMAL);
}
@@ -120,7 +120,7 @@ void Menu::AppendDelegateMenuItem(int item_id) {
}
void Menu::AddDelegateMenuItem(int index, int item_id) {
- AddMenuItem(index, item_id, string16(), Menu::NORMAL);
+ AddMenuItem(index, item_id, base::string16(), Menu::NORMAL);
}
void Menu::AppendSeparator() {
@@ -128,14 +128,14 @@ void Menu::AppendSeparator() {
}
void Menu::AppendMenuItemWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
AddMenuItemWithIcon(-1, item_id, label, icon);
}
void Menu::AddMenuItemWithIcon(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
AddMenuItemInternal(index, item_id, label, icon, Menu::NORMAL);
}
diff --git a/chromium/ui/views/controls/menu/menu.h b/chromium/ui/views/controls/menu/menu.h
index 5a774df7320..099a98ee543 100644
--- a/chromium/ui/views/controls/menu/menu.h
+++ b/chromium/ui/views/controls/menu/menu.h
@@ -45,7 +45,7 @@ class VIEWS_EXPORT Menu {
virtual bool IsItemDefault(int id) const;
// The string shown for the menu item.
- virtual string16 GetLabel(int id) const;
+ virtual base::string16 GetLabel(int id) const;
// The delegate needs to implement this function if it wants to display
// the shortcut text next to each menu item. If there is an accelerator
@@ -94,7 +94,7 @@ class VIEWS_EXPORT Menu {
// Controller
virtual bool SupportsCommand(int id) const;
virtual bool IsCommandEnabled(int id) const;
- virtual bool GetContextualLabel(int id, string16* out) const;
+ virtual bool GetContextualLabel(int id, base::string16* out) const;
virtual void ExecuteCommand(int id) {
}
@@ -151,35 +151,37 @@ class VIEWS_EXPORT Menu {
// label The text label shown.
// type The type of item.
void AppendMenuItem(int item_id,
- const string16& label,
+ const base::string16& label,
MenuItemType type);
void AddMenuItem(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
MenuItemType type);
// Append a submenu to this menu.
// The returned pointer is owned by this menu.
Menu* AppendSubMenu(int item_id,
- const string16& label);
- Menu* AddSubMenu(int index, int item_id, const string16& label);
+ const base::string16& label);
+ Menu* AddSubMenu(int index, int item_id, const base::string16& label);
// Append a submenu with an icon to this menu
// The returned pointer is owned by this menu.
// Unless the icon is empty, calling this function forces the Menu class
// to draw the menu, instead of relying on Windows.
Menu* AppendSubMenuWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
virtual Menu* AddSubMenuWithIcon(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) = 0;
// This is a convenience for standard text label menu items where the label
// is provided with this call.
- void AppendMenuItemWithLabel(int item_id, const string16& label);
- void AddMenuItemWithLabel(int index, int item_id, const string16& label);
+ void AppendMenuItemWithLabel(int item_id, const base::string16& label);
+ void AddMenuItemWithLabel(int index,
+ int item_id,
+ const base::string16& label);
// This is a convenience for text label menu items where the label is
// provided by the delegate.
@@ -194,11 +196,11 @@ class VIEWS_EXPORT Menu {
// needs an icon. Calling this function forces the Menu class to draw
// the menu, instead of relying on Windows.
void AppendMenuItemWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
virtual void AddMenuItemWithIcon(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
// Enables or disables the item with the specified id.
@@ -206,7 +208,7 @@ class VIEWS_EXPORT Menu {
virtual void EnableMenuItemAt(int index, bool enabled) = 0;
// Sets menu label at specified index.
- virtual void SetMenuLabel(int item_id, const string16& label) = 0;
+ virtual void SetMenuLabel(int item_id, const base::string16& label) = 0;
// Sets an icon for an item with a given item_id. Calling this function
// also forces the Menu class to draw the menu, instead of relying on Windows.
@@ -234,7 +236,7 @@ class VIEWS_EXPORT Menu {
virtual void AddMenuItemInternal(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon,
MenuItemType type) = 0;
diff --git a/chromium/ui/views/controls/menu/menu_config.cc b/chromium/ui/views/controls/menu/menu_config.cc
index 1c34ac0b3e0..9eaba83f6db 100644
--- a/chromium/ui/views/controls/menu/menu_config.cc
+++ b/chromium/ui/views/controls/menu/menu_config.cc
@@ -5,14 +5,11 @@
#include "ui/views/controls/menu/menu_config.h"
#include "build/build_config.h"
-#include "ui/base/layout.h"
-#include "ui/native_theme/native_theme.h"
namespace views {
MenuConfig::MenuConfig(const ui::NativeTheme* theme)
- : text_color(SK_ColorBLACK),
- arrow_color(SK_ColorBLACK),
+ : arrow_color(SK_ColorBLACK),
menu_vertical_border_size(3),
menu_horizontal_border_size(0),
submenu_horizontal_inset(3),
@@ -28,8 +25,6 @@ MenuConfig::MenuConfig(const ui::NativeTheme* theme)
check_width(16),
check_height(16),
radio_width(16),
- radio_height(16),
- arrow_height(9),
arrow_width(9),
gutter_width(0),
separator_height(11),
@@ -48,12 +43,6 @@ MenuConfig::MenuConfig(const ui::NativeTheme* theme)
native_theme(theme),
show_delay(400),
corner_radius(0) {
- // Use 40px tall menu items when running in touch optimized mode.
- // For Windows use 40px tall menu items when running in touch optimized mode.
- if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) {
- item_top_margin = item_no_icon_top_margin = 12;
- item_bottom_margin = item_no_icon_bottom_margin = 13;
- }
Init(theme);
}
diff --git a/chromium/ui/views/controls/menu/menu_config.h b/chromium/ui/views/controls/menu/menu_config.h
index 96eb21ac219..3cdbccdbf4d 100644
--- a/chromium/ui/views/controls/menu/menu_config.h
+++ b/chromium/ui/views/controls/menu/menu_config.h
@@ -6,7 +6,7 @@
#define UI_VIEWS_CONTROLS_MENU_MENU_CONFIG_H_
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/views_export.h"
namespace ui {
@@ -23,11 +23,8 @@ struct VIEWS_EXPORT MenuConfig {
static const MenuConfig& instance(const ui::NativeTheme* theme);
- // Font used by menus.
- gfx::Font font;
-
- // Normal text color.
- SkColor text_color;
+ // Font list used by menus.
+ gfx::FontList font_list;
// Color for the arrow to scroll bookmarks.
SkColor arrow_color;
@@ -70,12 +67,10 @@ struct VIEWS_EXPORT MenuConfig {
int check_width;
int check_height;
- // Size of the radio bullet.
+ // Width of the radio bullet.
int radio_width;
- int radio_height;
- // Size of the submenu arrow.
- int arrow_height;
+ // Width of the submenu arrow.
int arrow_width;
// Width of the gutter. Only used if render_gutter is true.
@@ -136,9 +131,7 @@ struct VIEWS_EXPORT MenuConfig {
void Init(const ui::NativeTheme* theme);
// TODO: temporary until we standardize.
-#if defined(USE_AURA)
void InitAura(const ui::NativeTheme* theme);
-#endif
};
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config_views.cc b/chromium/ui/views/controls/menu/menu_config_aura.cc
index d0b48443711..2e464d22488 100644
--- a/chromium/ui/views/controls/menu/menu_config_views.cc
+++ b/chromium/ui/views/controls/menu/menu_config_aura.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -30,20 +30,16 @@ void MenuConfig::Init(const ui::NativeTheme* theme) {
#endif
void MenuConfig::InitAura(const ui::NativeTheme* theme) {
- text_color = theme->GetSystemColor(
- ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor);
submenu_horizontal_inset = 1;
arrow_to_edge_padding = 20;
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- arrow_width =
- rb.GetImageNamed(IDR_MENU_HIERARCHY_ARROW).ToImageSkia()->width();
+ arrow_width = rb.GetImageNamed(IDR_MENU_HIERARCHY_ARROW).Width();
gfx::ImageSkia check = GetMenuCheckImage(false);
check_height = check.height();
item_min_height = 29;
separator_spacing_height = 7;
separator_lower_height = 8;
separator_upper_height = 8;
- font = rb.GetFont(ResourceBundle::BaseFont);
label_to_arrow_padding = 20;
label_to_minor_text_padding = 20;
always_use_icon_to_label_padding = true;
diff --git a/chromium/ui/views/controls/menu/menu_config_mac.cc b/chromium/ui/views/controls/menu/menu_config_mac.cc
new file mode 100644
index 00000000000..dd38e72fe7e
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_config_mac.cc
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_config.h"
+
+#include "grit/ui_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/native_theme/native_theme_mac.h"
+#include "ui/views/controls/menu/menu_image_util.h"
+
+namespace views {
+
+void MenuConfig::Init(const ui::NativeTheme* theme) {
+ NOTIMPLEMENTED();
+}
+
+// static
+const MenuConfig& MenuConfig::instance(const ui::NativeTheme* theme) {
+ CR_DEFINE_STATIC_LOCAL(
+ MenuConfig, mac_instance, (theme ? theme : ui::NativeTheme::instance()));
+ return mac_instance;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config_win.cc b/chromium/ui/views/controls/menu/menu_config_win.cc
index e0bde54c30b..4ef5fac3070 100644
--- a/chromium/ui/views/controls/menu/menu_config_win.cc
+++ b/chromium/ui/views/controls/menu/menu_config_win.cc
@@ -13,11 +13,8 @@
#include "base/win/win_util.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/gfx/color_utils.h"
-#include "ui/native_theme/native_theme_win.h"
-
-#if defined(USE_AURA)
#include "ui/native_theme/native_theme_aura.h"
-#endif
+#include "ui/native_theme/native_theme_win.h"
using ui::NativeTheme;
using ui::NativeThemeWin;
@@ -25,15 +22,10 @@ using ui::NativeThemeWin;
namespace views {
void MenuConfig::Init(const NativeTheme* theme) {
-#if defined(USE_AURA)
if (theme == ui::NativeThemeAura::instance()) {
InitAura(theme);
return;
}
-#endif
- text_color = NativeThemeWin::instance()->GetThemeColorWithDefault(
- NativeThemeWin::MENU, MENU_POPUPITEM, MPI_NORMAL, TMT_TEXTCOLOR,
- COLOR_MENUTEXT);
arrow_color = color_utils::GetSysSkColor(COLOR_MENUTEXT);
@@ -43,7 +35,7 @@ void MenuConfig::Init(const NativeTheme* theme) {
{
base::win::ScopedHFONT new_font(CreateFontIndirect(&metrics.lfMenuFont));
DLOG_ASSERT(new_font.Get());
- font = gfx::Font(new_font);
+ font_list = gfx::FontList(gfx::Font(new_font));
}
NativeTheme::ExtraParams extra;
extra.menu_check.is_radio = false;
@@ -61,23 +53,18 @@ void MenuConfig::Init(const NativeTheme* theme) {
extra.menu_check.is_radio = true;
gfx::Size radio_size = NativeThemeWin::instance()->GetPartSize(
NativeTheme::kMenuCheck, NativeTheme::kNormal, extra);
- if (!radio_size.IsEmpty()) {
+ if (!radio_size.IsEmpty())
radio_width = radio_size.width();
- radio_height = radio_size.height();
- } else {
+ else
radio_width = GetSystemMetrics(SM_CXMENUCHECK);
- radio_height = GetSystemMetrics(SM_CYMENUCHECK);
- }
gfx::Size arrow_size = NativeThemeWin::instance()->GetPartSize(
NativeTheme::kMenuPopupArrow, NativeTheme::kNormal, extra);
if (!arrow_size.IsEmpty()) {
arrow_width = arrow_size.width();
- arrow_height = arrow_size.height();
} else {
// Sadly I didn't see a specify metrics for this.
arrow_width = GetSystemMetrics(SM_CXMENUCHECK);
- arrow_height = GetSystemMetrics(SM_CYMENUCHECK);
}
BOOL show_cues;
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index 3b0e5d552c0..d5b5a84e8f1 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -4,23 +4,18 @@
#include "ui/views/controls/menu/menu_controller.h"
-#if defined(OS_WIN)
-#include <windowsx.h>
-#endif
-
#include "base/i18n/case_conversion.h"
#include "base/i18n/rtl.h"
-#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "ui/base/dragdrop/drag_utils.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/events/event_constants.h"
+#include "ui/events/event.h"
#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/vector2d.h"
#include "ui/native_theme/native_theme.h"
@@ -28,32 +23,26 @@
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_controller_delegate.h"
#include "ui/views/controls/menu/menu_host_root_view.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/controls/menu/menu_message_loop.h"
#include "ui/views/controls/menu/menu_scroll_view_container.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/drag_utils.h"
-#include "ui/views/event_utils.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/mouse_constants.h"
+#include "ui/views/view.h"
#include "ui/views/view_constants.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/tooltip_manager.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#endif
-
#if defined(OS_WIN)
-#include "ui/views/win/hwnd_message_handler.h"
+#include "ui/base/win/internal_constants.h"
+#include "ui/gfx/win/dpi.h"
#include "ui/views/win/hwnd_util.h"
#endif
-#if defined(USE_X11)
-#include <X11/Xlib.h>
-#endif
-
using base::Time;
using base::TimeDelta;
using ui::OSExchangeData;
@@ -87,17 +76,17 @@ const int kBubbleTipSizeTopBottom = 11;
const float kMaximumLengthMovedToActivate = 4.0f;
// Returns true if the mnemonic of |menu| matches key.
-bool MatchesMnemonic(MenuItemView* menu, char16 key) {
- return menu->GetMnemonic() == key;
+bool MatchesMnemonic(MenuItemView* menu, base::char16 key) {
+ return key != 0 && menu->GetMnemonic() == key;
}
// Returns true if |menu| doesn't have a mnemonic and first character of the its
// title is |key|.
-bool TitleMatchesMnemonic(MenuItemView* menu, char16 key) {
+bool TitleMatchesMnemonic(MenuItemView* menu, base::char16 key) {
if (menu->GetMnemonic())
return false;
- string16 lower_title = base::i18n::ToLower(menu->title());
+ base::string16 lower_title = base::i18n::ToLower(menu->title());
return !lower_title.empty() && lower_title[0] == key;
}
@@ -279,8 +268,9 @@ struct MenuController::SelectByCharDetails {
MenuController::State::State()
: item(NULL),
submenu_open(false),
- anchor(MenuItemView::TOPLEFT),
- context_menu(false) {}
+ anchor(MENU_ANCHOR_TOPLEFT),
+ context_menu(false) {
+}
MenuController::State::~State() {}
@@ -298,7 +288,7 @@ MenuItemView* MenuController::Run(Widget* parent,
MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
+ MenuAnchorPosition position,
bool context_menu,
int* result_event_flags) {
exit_type_ = EXIT_NONE;
@@ -385,7 +375,7 @@ MenuItemView* MenuController::Run(Widget* parent,
// Close any open menus.
SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
-#if defined(OS_WIN) && defined(USE_AURA)
+#if defined(OS_WIN)
// On Windows, if we select the menu item by touch and if the window at the
// location is another window on the same thread, that window gets a
// WM_MOUSEACTIVATE message and ends up activating itself, which is not
@@ -400,7 +390,7 @@ MenuItemView* MenuController::Run(Widget* parent,
HWND window = ::WindowFromPoint(cursor_pos);
if (::GetWindowThreadProcessId(window, NULL) ==
::GetCurrentThreadId()) {
- ::SetProp(window, views::kIgnoreTouchMouseActivateForWindow,
+ ::SetProp(window, ui::kIgnoreTouchMouseActivateForWindow,
reinterpret_cast<HANDLE>(true));
}
}
@@ -596,13 +586,11 @@ void MenuController::OnMouseEntered(SubmenuView* source,
// do anything here.
}
-#if defined(USE_AURA)
bool MenuController::OnMouseWheel(SubmenuView* source,
const ui::MouseWheelEvent& event) {
MenuPart part = GetMenuPart(source, event.location());
return part.submenu && part.submenu->OnMouseWheel(event);
}
-#endif
void MenuController::OnGestureEvent(SubmenuView* source,
ui::GestureEvent* event) {
@@ -809,6 +797,7 @@ void MenuController::OnWidgetDestroying(Widget* widget) {
DCHECK_EQ(owner_, widget);
owner_->RemoveObserver(this);
owner_ = NULL;
+ message_loop_->ClearOwner();
}
// static
@@ -875,7 +864,7 @@ void MenuController::SetSelection(MenuItemView* menu_item,
(MenuDepth(menu_item) != 1 ||
menu_item->GetType() != MenuItemView::SUBMENU)) {
menu_item->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_FOCUS, true);
+ ui::AX_EVENT_FOCUS, true);
}
}
@@ -912,14 +901,7 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source,
#if defined(OS_WIN)
// We're going to close and we own the mouse capture. We need to repost the
// mouse down, otherwise the window the user clicked on won't get the event.
- if (!state_.item) {
- // We some times get an event after closing all the menus. Ignore it. Make
- // sure the menu is in fact not visible. If the menu is visible, then
- // we're in a bad state where we think the menu isn't visibile but it is.
- DCHECK(!source->GetWidget()->IsVisible());
- } else {
- RepostEvent(source, event);
- }
+ RepostEvent(source, event);
#endif
// And close.
@@ -936,14 +918,15 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source,
}
Cancel(exit_type);
-#if defined(USE_AURA) && !defined(OS_WIN)
+#if defined(OS_CHROMEOS)
// We're going to exit the menu and want to repost the event so that is
// is handled normally after the context menu has exited. We call
// RepostEvent after Cancel so that mouse capture has been released so
// that finding the event target is unaffected by the current capture.
RepostEvent(source, event);
#endif
-
+ // Do not repost events for Linux Aura because this behavior is more
+ // consistent with the behavior of other Linux apps.
return;
}
@@ -982,7 +965,7 @@ void MenuController::StartDrag(SubmenuView* source,
OSExchangeData data;
item->GetDelegate()->WriteDragData(item, &data);
- drag_utils::SetDragImageOnDataObject(*canvas, item->size(),
+ drag_utils::SetDragImageOnDataObject(*canvas,
press_loc.OffsetFromOrigin(),
&data);
StopScrolling();
@@ -1002,94 +985,6 @@ void MenuController::StartDrag(SubmenuView* source,
} // else case, someone canceled us, don't do anything
}
-#if defined(OS_WIN)
-bool MenuController::Dispatch(const MSG& msg) {
- DCHECK(blocking_run_);
-
- if (exit_type_ == EXIT_ALL || exit_type_ == EXIT_DESTROYED) {
- // We must translate/dispatch the message here, otherwise we would drop
- // the message on the floor.
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- return false;
- }
-
- // NOTE: we don't get WM_ACTIVATE or anything else interesting in here.
- switch (msg.message) {
- case WM_CONTEXTMENU: {
- MenuItemView* item = pending_state_.item;
- if (item && item->GetRootMenuItem() != item) {
- gfx::Point screen_loc(0, item->height());
- View::ConvertPointToScreen(item, &screen_loc);
- ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE;
- if (GET_X_LPARAM(msg.lParam) == -1 && GET_Y_LPARAM(msg.lParam) == -1)
- source_type = ui::MENU_SOURCE_KEYBOARD;
- item->GetDelegate()->ShowContextMenu(item, item->GetCommand(),
- screen_loc, source_type);
- }
- return true;
- }
-
- // NOTE: focus wasn't changed when the menu was shown. As such, don't
- // dispatch key events otherwise the focused window will get the events.
- case WM_KEYDOWN: {
- bool result = OnKeyDown(ui::KeyboardCodeFromNative(msg));
- TranslateMessage(&msg);
- return result;
- }
- case WM_CHAR:
- return !SelectByChar(static_cast<char16>(msg.wParam));
- case WM_KEYUP:
- return true;
-
- case WM_SYSKEYUP:
- // We may have been shown on a system key, as such don't do anything
- // here. If another system key is pushed we'll get a WM_SYSKEYDOWN and
- // close the menu.
- return true;
-
- case WM_CANCELMODE:
- case WM_SYSKEYDOWN:
- // Exit immediately on system keys.
- Cancel(EXIT_ALL);
- return false;
-
- default:
- break;
- }
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- return exit_type_ == EXIT_NONE;
-}
-#elif defined(USE_AURA)
-bool MenuController::Dispatch(const base::NativeEvent& event) {
- if (exit_type_ == EXIT_ALL || exit_type_ == EXIT_DESTROYED) {
- aura::Env::GetInstance()->GetDispatcher()->Dispatch(event);
- return false;
- }
- // Activates mnemonics only when it it pressed without modifiers except for
- // caps and shift.
- int flags = ui::EventFlagsFromNative(event) &
- ~ui::EF_CAPS_LOCK_DOWN & ~ui::EF_SHIFT_DOWN;
- if (flags == ui::EF_NONE) {
- switch (ui::EventTypeFromNative(event)) {
- case ui::ET_KEY_PRESSED:
- if (!OnKeyDown(ui::KeyboardCodeFromNative(event)))
- return false;
-
- return !SelectByChar(ui::KeyboardCodeFromNative(event));
- case ui::ET_KEY_RELEASED:
- return true;
- default:
- break;
- }
- }
-
- aura::Env::GetInstance()->GetDispatcher()->Dispatch(event);
- return exit_type_ == EXIT_NONE;
-}
-#endif
-
bool MenuController::OnKeyDown(ui::KeyboardCode key_code) {
DCHECK(blocking_run_);
@@ -1124,7 +1019,7 @@ bool MenuController::OnKeyDown(ui::KeyboardCode key_code) {
break;
case ui::VKEY_F4:
- if (!accept_on_f4_)
+ if (!is_combobox_)
break;
// Fallthrough to accept on F4, so combobox menus match Windows behavior.
case ui::VKEY_RETURN:
@@ -1156,11 +1051,6 @@ bool MenuController::OnKeyDown(ui::KeyboardCode key_code) {
CloseSubmenu();
break;
-#if defined(OS_WIN)
- case VK_APPS:
- break;
-#endif
-
default:
break;
}
@@ -1191,8 +1081,9 @@ MenuController::MenuController(ui::NativeTheme* theme,
menu_config_(theme),
closing_event_time_(base::TimeDelta()),
menu_start_time_(base::TimeTicks()),
- accept_on_f4_(false),
- item_selected_by_touch_(false) {
+ is_combobox_(false),
+ item_selected_by_touch_(false),
+ message_loop_(MenuMessageLoop::Create()) {
active_instance_ = this;
}
@@ -1206,6 +1097,10 @@ MenuController::~MenuController() {
StopCancelAllTimer();
}
+void MenuController::RunMessageLoop(bool nested_menu) {
+ message_loop_->Run(this, owner_, nested_menu);
+}
+
MenuController::SendAcceleratorResultType
MenuController::SendAcceleratorToHotTrackedView() {
CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item);
@@ -1220,10 +1115,9 @@ MenuController::SendAcceleratorResultType
ACCELERATOR_PROCESSED : ACCELERATOR_PROCESSED_EXIT;
}
-void MenuController::UpdateInitialLocation(
- const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
- bool context_menu) {
+void MenuController::UpdateInitialLocation(const gfx::Rect& bounds,
+ MenuAnchorPosition position,
+ bool context_menu) {
pending_state_.context_menu = context_menu;
pending_state_.initial_bounds = bounds;
if (bounds.height() > 1) {
@@ -1234,10 +1128,10 @@ void MenuController::UpdateInitialLocation(
// Reverse anchor position for RTL languages.
if (base::i18n::IsRTL() &&
- (position == MenuItemView::TOPRIGHT ||
- position == MenuItemView::TOPLEFT)) {
- pending_state_.anchor = position == MenuItemView::TOPRIGHT ?
- MenuItemView::TOPLEFT : MenuItemView::TOPRIGHT;
+ (position == MENU_ANCHOR_TOPRIGHT || position == MENU_ANCHOR_TOPLEFT)) {
+ pending_state_.anchor = position == MENU_ANCHOR_TOPRIGHT
+ ? MENU_ANCHOR_TOPLEFT
+ : MENU_ANCHOR_TOPRIGHT;
} else {
pending_state_.anchor = position;
}
@@ -1246,7 +1140,7 @@ void MenuController::UpdateInitialLocation(
// avoid repeated system queries for the info.
pending_state_.monitor_bounds = GetScreen()->GetDisplayNearestPoint(
bounds.origin()).work_area();
-#if defined(USE_ASH)
+
if (!pending_state_.monitor_bounds.Contains(bounds)) {
// Use the monitor area if the work area doesn't contain the bounds. This
// handles showing a menu from the launcher.
@@ -1255,7 +1149,6 @@ void MenuController::UpdateInitialLocation(
if (monitor_area.Contains(bounds))
pending_state_.monitor_bounds = monitor_area;
}
-#endif
}
void MenuController::Accept(MenuItemView* item, int event_flags) {
@@ -1293,7 +1186,7 @@ bool MenuController::ShowSiblingMenu(SubmenuView* source,
// if there is a sibling menu we should show.
gfx::Point screen_point(mouse_location);
View::ConvertPointToScreen(source_view, &screen_point);
- MenuItemView::AnchorPosition anchor;
+ MenuAnchorPosition anchor;
bool has_mnemonics;
MenuButton* button = NULL;
MenuItemView* alt_menu = source->GetMenuItem()->GetDelegate()->
@@ -1717,11 +1610,11 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
x += 1;
y = state_.initial_bounds.bottom();
- if (state_.anchor == MenuItemView::TOPRIGHT) {
+ if (state_.anchor == MENU_ANCHOR_TOPRIGHT) {
x = x + state_.initial_bounds.width() - pref.width();
if (menu_config.offset_context_menus && state_.context_menu)
x -= 1;
- } else if (state_.anchor == MenuItemView::BOTTOMCENTER) {
+ } else if (state_.anchor == MENU_ANCHOR_BOTTOMCENTER) {
x = x - (pref.width() - state_.initial_bounds.width()) / 2;
if (pref.height() >
state_.initial_bounds.y() + kCenteredContextMenuYOffset) {
@@ -1770,7 +1663,7 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
// The menu should never overlap the owning button. So move it.
// We use the anchor view style to determine the preferred position
// relative to the owning button.
- if (state_.anchor == MenuItemView::TOPLEFT) {
+ if (state_.anchor == MENU_ANCHOR_TOPLEFT) {
// The menu starts with the same x coordinate as the owning button.
if (x + state_.initial_bounds.width() + pref.width() >
state_.monitor_bounds.right())
@@ -1883,16 +1776,16 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
int max_height = state_.monitor_bounds.height();
// In case of bubbles, the maximum width is limited by the space
// between the display corner and the target area + the tip size.
- if (state_.anchor == MenuItemView::BUBBLE_LEFT) {
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_LEFT) {
max_width = owner_bounds.x() - state_.monitor_bounds.x() +
kBubbleTipSizeLeftRight;
- } else if (state_.anchor == MenuItemView::BUBBLE_RIGHT) {
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT) {
max_width = state_.monitor_bounds.right() - owner_bounds.right() +
kBubbleTipSizeLeftRight;
- } else if (state_.anchor == MenuItemView::BUBBLE_ABOVE) {
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE) {
max_height = owner_bounds.y() - state_.monitor_bounds.y() +
kBubbleTipSizeTopBottom;
- } else if (state_.anchor == MenuItemView::BUBBLE_BELOW) {
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
max_height = state_.monitor_bounds.bottom() - owner_bounds.bottom() +
kBubbleTipSizeTopBottom;
}
@@ -1907,9 +1800,9 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
item->GetDelegate()->GetMaxWidthForMenu(item)));
int x, y;
- if (state_.anchor == MenuItemView::BUBBLE_ABOVE ||
- state_.anchor == MenuItemView::BUBBLE_BELOW) {
- if (state_.anchor == MenuItemView::BUBBLE_ABOVE)
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE ||
+ state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE)
y = owner_bounds.y() - pref.height() + kBubbleTipSizeTopBottom;
else
y = owner_bounds.bottom() - kBubbleTipSizeTopBottom;
@@ -1924,7 +1817,7 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
submenu->GetScrollViewContainer()->SetBubbleArrowOffset(
pref.width() / 2 - x + x_old);
} else {
- if (state_.anchor == MenuItemView::BUBBLE_RIGHT)
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT)
x = owner_bounds.right() - kBubbleTipSizeLeftRight;
else
x = owner_bounds.x() - pref.width() + kBubbleTipSizeLeftRight;
@@ -2046,8 +1939,8 @@ void MenuController::CloseSubmenu() {
MenuController::SelectByCharDetails MenuController::FindChildForMnemonic(
MenuItemView* parent,
- char16 key,
- bool (*match_function)(MenuItemView* menu, char16 mnemonic)) {
+ base::char16 key,
+ bool (*match_function)(MenuItemView* menu, base::char16 mnemonic)) {
SubmenuView* submenu = parent->GetSubmenu();
DCHECK(submenu);
SelectByCharDetails details;
@@ -2098,9 +1991,9 @@ bool MenuController::AcceptOrSelect(MenuItemView* parent,
return false;
}
-bool MenuController::SelectByChar(char16 character) {
- char16 char_array[] = { character, 0 };
- char16 key = base::i18n::ToLower(char_array)[0];
+bool MenuController::SelectByChar(base::char16 character) {
+ base::char16 char_array[] = { character, 0 };
+ base::char16 key = base::i18n::ToLower(char_array)[0];
MenuItemView* item = pending_state_.item;
if (!item->HasSubmenu() || !item->GetSubmenu()->IsShowing())
item = item->GetParentMenuItem();
@@ -2116,61 +2009,114 @@ bool MenuController::SelectByChar(char16 character) {
if (details.first_match != -1)
return AcceptOrSelect(item, details);
- // If no mnemonics found, look at first character of titles.
- details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic);
- if (details.first_match != -1)
- return AcceptOrSelect(item, details);
+ if (is_combobox_) {
+ item->GetSubmenu()->GetTextInputClient()->InsertChar(character, 0);
+ } else {
+ // If no mnemonics found, look at first character of titles.
+ details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic);
+ if (details.first_match != -1)
+ return AcceptOrSelect(item, details);
+ }
return false;
}
void MenuController::RepostEvent(SubmenuView* source,
const ui::LocatedEvent& event) {
+ if (!event.IsMouseEvent()) {
+ // TODO(rbyers): Gesture event repost is tricky to get right
+ // crbug.com/170987.
+ DCHECK(event.IsGestureEvent());
+ return;
+ }
+
+#if defined(OS_WIN)
+ if (!state_.item) {
+ // We some times get an event after closing all the menus. Ignore it. Make
+ // sure the menu is in fact not visible. If the menu is visible, then
+ // we're in a bad state where we think the menu isn't visibile but it is.
+ DCHECK(!source->GetWidget()->IsVisible());
+ return;
+ }
+
+ state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture();
+#endif
+
gfx::Point screen_loc(event.location());
View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
-
gfx::NativeView native_view = source->GetWidget()->GetNativeView();
+ if (!native_view)
+ return;
+
gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view);
gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc);
- if (!window)
- return;
-
#if defined(OS_WIN)
- // Release the capture.
- SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu();
- submenu->ReleaseCapture();
-
- gfx::NativeView view = submenu->GetWidget()->GetNativeView();
- if (view) {
- DWORD view_tid = GetWindowThreadProcessId(HWNDForNativeView(view), NULL);
- if (view_tid != GetWindowThreadProcessId(HWNDForNativeView(window), NULL)) {
+ // Convert screen_loc to pixels for the Win32 API's like WindowFromPoint,
+ // PostMessage/SendMessage to work correctly. These API's expect the
+ // coordinates to be in pixels.
+ // PostMessage() to metro windows isn't allowed (access will be denied). Don't
+ // try to repost with Win32 if the window under the mouse press is in metro.
+ if (!ViewsDelegate::views_delegate ||
+ !ViewsDelegate::views_delegate->IsWindowInMetro(window)) {
+ gfx::Point screen_loc_pixels = gfx::win::DIPToScreenPoint(screen_loc);
+ HWND target_window = window ? HWNDForNativeWindow(window) :
+ WindowFromPoint(screen_loc_pixels.ToPOINT());
+ HWND source_window = HWNDForNativeView(native_view);
+ if (!target_window || !source_window ||
+ GetWindowThreadProcessId(source_window, NULL) !=
+ GetWindowThreadProcessId(target_window, NULL)) {
// Even though we have mouse capture, windows generates a mouse event if
// the other window is in a separate thread. Only repost an event if
- // |view| was created on the same thread, else the target window can get
- // double events leading to bad behavior.
+ // |target_window| and |source_window| were created on the same thread,
+ // else double events can occur and lead to bad behavior.
return;
}
- }
-#endif
- scoped_ptr<ui::LocatedEvent> clone;
- if (event.IsMouseEvent()) {
- clone.reset(new ui::MouseEvent(static_cast<const ui::MouseEvent&>(event)));
- } else if (event.IsGestureEvent()) {
- // TODO(rbyers): Gesture event repost is tricky to get right
- // crbug.com/170987.
- return;
- } else {
- NOTREACHED();
+ // Determine whether the click was in the client area or not.
+ // NOTE: WM_NCHITTEST coordinates are relative to the screen.
+ LPARAM coords = MAKELPARAM(screen_loc_pixels.x(), screen_loc_pixels.y());
+ LRESULT nc_hit_result = SendMessage(target_window, WM_NCHITTEST, 0, coords);
+ const bool client_area = nc_hit_result == HTCLIENT;
+
+ // TODO(sky): this isn't right. The event to generate should correspond with
+ // the event we just got. MouseEvent only tells us what is down, which may
+ // differ. Need to add ability to get changed button from MouseEvent.
+ int event_type;
+ int flags = event.flags();
+ if (flags & ui::EF_LEFT_MOUSE_BUTTON) {
+ event_type = client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN;
+ } else if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) {
+ event_type = client_area ? WM_MBUTTONDOWN : WM_NCMBUTTONDOWN;
+ } else if (flags & ui::EF_RIGHT_MOUSE_BUTTON) {
+ event_type = client_area ? WM_RBUTTONDOWN : WM_NCRBUTTONDOWN;
+ } else {
+ NOTREACHED();
+ return;
+ }
+
+ int window_x = screen_loc_pixels.x();
+ int window_y = screen_loc_pixels.y();
+ if (client_area) {
+ POINT pt = { window_x, window_y };
+ ScreenToClient(target_window, &pt);
+ window_x = pt.x;
+ window_y = pt.y;
+ }
+
+ WPARAM target = client_area ? event.native_event().wParam : nc_hit_result;
+ LPARAM window_coords = MAKELPARAM(window_x, window_y);
+ PostMessage(target_window, event_type, target, window_coords);
return;
}
- clone->set_location(screen_loc);
+#endif
+ // Non-Windows Aura or |window| is in metro mode.
+ if (!window)
+ return;
- RepostLocatedEvent(window, *clone);
+ message_loop_->RepostEventToWindow(event, window, screen_loc);
}
-
void MenuController::SetDropMenuItem(
MenuItemView* new_target,
MenuDelegate::DropPosition new_position) {
@@ -2230,12 +2176,13 @@ void MenuController::UpdateActiveMouseView(SubmenuView* event_source,
target_menu, active_mouse_view, &target_point);
ui::MouseEvent mouse_entered_event(ui::ET_MOUSE_ENTERED,
target_point, target_point,
- 0);
+ 0, 0);
active_mouse_view->OnMouseEntered(mouse_entered_event);
ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED,
target_point, target_point,
- event.flags());
+ event.flags(),
+ event.changed_button_flags());
active_mouse_view->OnMousePressed(mouse_pressed_event);
}
}
@@ -2245,7 +2192,8 @@ void MenuController::UpdateActiveMouseView(SubmenuView* event_source,
View::ConvertPointToTarget(target_menu, active_mouse_view, &target_point);
ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED,
target_point, target_point,
- event.flags());
+ event.flags(),
+ event.changed_button_flags());
active_mouse_view->OnMouseDragged(mouse_dragged_event);
}
}
@@ -2261,7 +2209,7 @@ void MenuController::SendMouseReleaseToActiveView(SubmenuView* event_source,
&target_loc);
View::ConvertPointFromScreen(active_mouse_view, &target_loc);
ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, target_loc, target_loc,
- event.flags());
+ event.flags(), event.changed_button_flags());
// Reset active mouse view before sending mouse released. That way if it calls
// back to us, we aren't in a weird state.
SetActiveMouseView(NULL);
@@ -2293,20 +2241,22 @@ View* MenuController::GetActiveMouseView() {
void MenuController::SetExitType(ExitType type) {
exit_type_ = type;
// Exit nested message loops as soon as possible. We do this as
- // MessageLoop::Dispatcher is only invoked before native events, which means
+ // MessagePumpDispatcher is only invoked before native events, which means
// its entirely possible for a Widget::CloseNow() task to be processed before
- // the next native message. By using QuitNow() we ensures the nested message
- // loop returns as soon as possible and avoids having deleted views classes
- // (such as widgets and rootviews) on the stack when the nested message loop
- // stops.
+ // the next native message. We quite the nested message loop as soon as
+ // possible to avoid having deleted views classes (such as widgets and
+ // rootviews) on the stack when the nested message loop stops.
//
- // It's safe to invoke QuitNow multiple times, it only effects the current
- // loop.
- bool quit_now = ShouldQuitNow() && exit_type_ != EXIT_NONE &&
+ // It's safe to invoke QuitNestedMessageLoop() multiple times, it only effects
+ // the current loop.
+ bool quit_now = message_loop_->ShouldQuitNow() && exit_type_ != EXIT_NONE &&
message_loop_depth_;
-
if (quit_now)
- base::MessageLoop::current()->QuitNow();
+ TerminateNestedMessageLoop();
+}
+
+void MenuController::TerminateNestedMessageLoop() {
+ message_loop_->QuitNow();
}
void MenuController::HandleMouseLocation(SubmenuView* source,
@@ -2341,4 +2291,10 @@ void MenuController::HandleMouseLocation(SubmenuView* source,
}
}
+gfx::Screen* MenuController::GetScreen() {
+ Widget* root = owner_ ? owner_->GetTopLevelWidget() : NULL;
+ return root ? gfx::Screen::GetScreenFor(root->GetNativeView())
+ : gfx::Screen::GetNativeScreen();
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h
index 1404d54e5d6..30c56f0f04b 100644
--- a/chromium/ui/views/controls/menu/menu_controller.h
+++ b/chromium/ui/views/controls/menu/menu_controller.h
@@ -13,30 +13,39 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/timer/timer.h"
+#include "ui/events/event.h"
#include "ui/events/event_constants.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_delegate.h"
-#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/widget/widget_observer.h"
-namespace ui {
-class NativeTheme;
-class OSExchangeData;
+namespace base {
+class MessagePumpDispatcher;
}
namespace gfx {
class Screen;
}
+namespace ui {
+class NativeTheme;
+class OSExchangeData;
+class ScopedEventDispatcher;
+}
namespace views {
class MenuButton;
class MenuHostRootView;
+class MenuItemView;
+class MenuMessageLoop;
class MouseEvent;
class SubmenuView;
class View;
namespace internal {
class MenuControllerDelegate;
+class MenuEventDispatcher;
+class MenuMessagePumpDispatcher;
class MenuRunnerImpl;
}
@@ -45,8 +54,7 @@ class MenuRunnerImpl;
// MenuController is used internally by the various menu classes to manage
// showing, selecting and drag/drop for menus. All relevant events are
// forwarded to the MenuController from SubmenuView and MenuHost.
-class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
- public WidgetObserver {
+class VIEWS_EXPORT MenuController : public WidgetObserver {
public:
// Enumeration of how the menu should exit.
enum ExitType {
@@ -74,7 +82,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
+ MenuAnchorPosition position,
bool context_menu,
int* event_flags);
@@ -84,8 +92,12 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// Whether or not drag operation is in progress.
bool drag_in_progress() const { return drag_in_progress_; }
+ // Returns the owner of child windows.
+ // WARNING: this may be NULL.
+ Widget* owner() { return owner_; }
+
// Get the anchor position wich is used to show this menu.
- MenuItemView::AnchorPosition GetAnchorPosition() { return state_.anchor; }
+ MenuAnchorPosition GetAnchorPosition() { return state_.anchor; }
// Cancels the current Run. See ExitType for a description of what happens
// with the various parameters.
@@ -101,7 +113,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// Returns the time from the event which closed the menu - or 0.
base::TimeDelta closing_event_time() const { return closing_event_time_; }
- void set_accept_on_f4(bool accept_on_f4) { accept_on_f4_ = accept_on_f4; }
+ void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; }
// Various events, forwarded from the submenu.
//
@@ -112,9 +124,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
void OnMouseReleased(SubmenuView* source, const ui::MouseEvent& event);
void OnMouseMoved(SubmenuView* source, const ui::MouseEvent& event);
void OnMouseEntered(SubmenuView* source, const ui::MouseEvent& event);
-#if defined(USE_AURA)
bool OnMouseWheel(SubmenuView* source, const ui::MouseWheelEvent& event);
-#endif
void OnGestureEvent(SubmenuView* source, ui::GestureEvent* event);
bool GetDropFormats(
@@ -142,7 +152,10 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
static void TurnOffMenuSelectionHoldForTest();
private:
+ friend class internal::MenuEventDispatcher;
+ friend class internal::MenuMessagePumpDispatcher;
friend class internal::MenuRunnerImpl;
+ friend class MenuControllerTest;
friend class MenuHostRootView;
friend class MenuItemView;
friend class SubmenuView;
@@ -194,7 +207,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
gfx::Rect initial_bounds;
// Position of the initial menu.
- MenuItemView::AnchorPosition anchor;
+ MenuAnchorPosition anchor;
// The direction child menus have opened in.
std::list<bool> open_leading;
@@ -253,10 +266,6 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
const ui::LocatedEvent& event);
void StartDrag(SubmenuView* source, const gfx::Point& location);
- // Dispatcher method. This returns true if the menu was canceled, or
- // if the message is such that the menu should be closed.
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
// Key processing. The return value of this is returned from Dispatch.
// In other words, if this returns false (which happens if escape was
// pressed, or a matching mnemonic was found) the message loop returns.
@@ -279,7 +288,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
SendAcceleratorResultType SendAcceleratorToHotTrackedView();
void UpdateInitialLocation(const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
+ MenuAnchorPosition position,
bool context_menu);
// Invoked when the user accepts the selected item. This is only used
@@ -416,8 +425,8 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// |match_function| is used to determine which menus match.
SelectByCharDetails FindChildForMnemonic(
MenuItemView* parent,
- char16 key,
- bool (*match_function)(MenuItemView* menu, char16 mnemonic));
+ base::char16 key,
+ bool (*match_function)(MenuItemView* menu, base::char16 mnemonic));
// Selects or accepts the appropriate menu item based on |details|. Returns
// true if |Accept| was invoked (which happens if there aren't multiple item
@@ -426,7 +435,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// Selects by mnemonic, and if that doesn't work tries the first character of
// the title. Returns true if a match was selected and the menu should exit.
- bool SelectByChar(char16 key);
+ bool SelectByChar(base::char16 key);
// For Windows and Aura we repost an event for some events that dismiss
// the context menu. The event is then reprocessed to cause its result
@@ -468,9 +477,12 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
void SetActiveMouseView(View* view);
View* GetActiveMouseView();
- // Sets exit type.
+ // Sets exit type. Calling this can terminate the active nested message-loop.
void SetExitType(ExitType type);
+ // Terminates the current nested message-loop.
+ void TerminateNestedMessageLoop();
+
// Returns true if SetExitType() should quit the message loop.
bool ShouldQuitNow() const;
@@ -584,12 +596,15 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// screen coordinates). Otherwise this will be (0, 0).
gfx::Point menu_start_mouse_press_loc_;
- // Whether the menu should accept on F4, like Windows native Combobox menus.
- bool accept_on_f4_;
+ // Controls behavior differences between a combobox and other types of menu
+ // (like a context menu).
+ bool is_combobox_;
// Set to true if the menu item was selected by touch.
bool item_selected_by_touch_;
+ scoped_ptr<MenuMessageLoop> message_loop_;
+
DISALLOW_COPY_AND_ASSIGN(MenuController);
};
diff --git a/chromium/ui/views/controls/menu/menu_controller_aura.cc b/chromium/ui/views/controls/menu/menu_controller_aura.cc
deleted file mode 100644
index 48bf3118ff6..00000000000
--- a/chromium/ui/views/controls/menu/menu_controller_aura.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/menu/menu_controller.h"
-
-#include "base/run_loop.h"
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/dispatcher_client.h"
-#include "ui/aura/client/drag_drop_client.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
-#include "ui/gfx/screen.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-namespace {
-
-// ActivationChangeObserverImpl is used to observe activation changes and close
-// the menu. Additionally it listens for the root window to be destroyed and
-// cancel the menu as well.
-class ActivationChangeObserverImpl
- : public aura::client::ActivationChangeObserver,
- public aura::WindowObserver,
- public ui::EventHandler {
- public:
- ActivationChangeObserverImpl(MenuController* controller,
- aura::Window* root)
- : controller_(controller),
- root_(root) {
- aura::client::GetActivationClient(root_)->AddObserver(this);
- root_->AddObserver(this);
- root_->AddPreTargetHandler(this);
- }
-
- virtual ~ActivationChangeObserverImpl() {
- Cleanup();
- }
-
- // aura::client::ActivationChangeObserver overrides:
- virtual void OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) OVERRIDE {
- if (!controller_->drag_in_progress())
- controller_->CancelAll();
- }
-
- // aura::WindowObserver overrides:
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
- Cleanup();
- }
-
- // ui::EventHandler overrides:
- virtual void OnCancelMode(ui::CancelModeEvent* event) OVERRIDE {
- controller_->CancelAll();
- }
-
- private:
- void Cleanup() {
- if (!root_)
- return;
- // The ActivationClient may have been destroyed by the time we get here.
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(root_);
- if (client)
- client->RemoveObserver(this);
- root_->RemovePreTargetHandler(this);
- root_->RemoveObserver(this);
- root_ = NULL;
- }
-
- MenuController* controller_;
- aura::Window* root_;
-
- DISALLOW_COPY_AND_ASSIGN(ActivationChangeObserverImpl);
-};
-
-aura::Window* GetOwnerRootWindow(views::Widget* owner) {
- return owner ? owner->GetNativeWindow()->GetRootWindow() : NULL;
-}
-
-} // namespace
-
-void MenuController::RunMessageLoop(bool nested_menu) {
- // |owner_| may be NULL.
- aura::Window* root = GetOwnerRootWindow(owner_);
- if (root) {
- scoped_ptr<ActivationChangeObserverImpl> observer;
- if (!nested_menu)
- observer.reset(new ActivationChangeObserverImpl(this, root));
- aura::client::GetDispatcherClient(root)->
- RunWithDispatcher(this, owner_->GetNativeWindow(), true);
- } else {
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoop::ScopedNestableTaskAllower allow(loop);
- base::RunLoop run_loop(this);
- run_loop.Run();
- }
-}
-
-bool MenuController::ShouldQuitNow() const {
- aura::Window* root = GetOwnerRootWindow(owner_);
- return !aura::client::GetDragDropClient(root) ||
- !aura::client::GetDragDropClient(root)->IsDragDropInProgress();
-}
-
-gfx::Screen* MenuController::GetScreen() {
- aura::Window* root = GetOwnerRootWindow(owner_);
- return root ?
- gfx::Screen::GetScreenFor(root) : gfx::Screen::GetNativeScreen();
-}
-
-
-} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
new file mode 100644
index 00000000000..1c98f95bc9c
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_controller.h"
+
+#include "base/run_loop.h"
+#include "ui/aura/scoped_window_targeter.h"
+#include "ui/aura/window.h"
+#include "ui/events/event_targeter.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/wm/public/dispatcher_client.h"
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_dispatcher.h"
+#elif defined(USE_X11)
+#include <X11/Xlib.h>
+#undef Bool
+#undef None
+#include "ui/events/test/events_test_utils_x11.h"
+#elif defined(USE_OZONE)
+#include "ui/events/event.h"
+#endif
+
+namespace views {
+
+namespace {
+
+class TestMenuItemView : public MenuItemView {
+ public:
+ TestMenuItemView() : MenuItemView(NULL) {}
+ virtual ~TestMenuItemView() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
+};
+
+class TestPlatformEventSource : public ui::PlatformEventSource {
+ public:
+ TestPlatformEventSource() {}
+ virtual ~TestPlatformEventSource() {}
+
+ uint32_t Dispatch(const ui::PlatformEvent& event) {
+ return DispatchEvent(event);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
+};
+
+class TestNullTargeter : public ui::EventTargeter {
+ public:
+ TestNullTargeter() {}
+ virtual ~TestNullTargeter() {}
+
+ virtual ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
+ ui::Event* event) OVERRIDE {
+ return NULL;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestNullTargeter);
+};
+
+class TestDispatcherClient : public aura::client::DispatcherClient {
+ public:
+ TestDispatcherClient() : dispatcher_(NULL) {}
+ virtual ~TestDispatcherClient() {}
+
+ base::MessagePumpDispatcher* dispatcher() {
+ return dispatcher_;
+ }
+
+ // aura::client::DispatcherClient:
+ virtual void PrepareNestedLoopClosures(
+ base::MessagePumpDispatcher* dispatcher,
+ base::Closure* run_closure,
+ base::Closure* quit_closure) OVERRIDE {
+ scoped_ptr<base::RunLoop> run_loop(new base::RunLoop());
+ *quit_closure = run_loop->QuitClosure();
+ *run_closure = base::Bind(&TestDispatcherClient::RunNestedDispatcher,
+ base::Unretained(this),
+ base::Passed(&run_loop),
+ dispatcher);
+ }
+
+ private:
+ void RunNestedDispatcher(scoped_ptr<base::RunLoop> run_loop,
+ base::MessagePumpDispatcher* dispatcher) {
+ base::AutoReset<base::MessagePumpDispatcher*> reset_dispatcher(&dispatcher_,
+ dispatcher);
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ run_loop->Run();
+ }
+
+ base::MessagePumpDispatcher* dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
+};
+
+} // namespace
+
+class MenuControllerTest : public ViewsTestBase {
+ public:
+ MenuControllerTest() : controller_(NULL) {}
+ virtual ~MenuControllerTest() {
+ ResetMenuController();
+ }
+
+ // Dispatches |count| number of items, each in a separate iteration of the
+ // message-loop, by posting a task.
+ void Step3_DispatchEvents(int count) {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ controller_->exit_type_ = MenuController::EXIT_ALL;
+
+ DispatchEvent();
+ if (count) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::Step3_DispatchEvents,
+ base::Unretained(this),
+ count - 1));
+ } else {
+ EXPECT_TRUE(run_loop_->running());
+ run_loop_->Quit();
+ }
+ }
+
+ // Runs a nested message-loop that does not involve the menu itself.
+ void Step2_RunNestedLoop() {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::Step3_DispatchEvents,
+ base::Unretained(this),
+ 3));
+ run_loop_.reset(new base::RunLoop());
+ run_loop_->Run();
+ }
+
+ void Step1_RunMenu() {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::Step2_RunNestedLoop,
+ base::Unretained(this)));
+ scoped_ptr<Widget> owner(CreateOwnerWidget());
+ RunMenu(owner.get());
+ }
+
+ scoped_ptr<Widget> CreateOwnerWidget() {
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+ widget->Show();
+
+ aura::client::SetDispatcherClient(
+ widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_);
+ return widget.Pass();
+ }
+
+ void RunMenu(views::Widget* owner) {
+ scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
+ ResetMenuController();
+ controller_ = new MenuController(NULL, true, NULL);
+ controller_->owner_ = owner;
+ controller_->showing_ = true;
+ controller_->SetSelection(menu_item.get(),
+ MenuController::SELECTION_UPDATE_IMMEDIATELY);
+ controller_->RunMessageLoop(false);
+ }
+
+#if defined(USE_X11)
+ void DispatchEscapeAndExpect(MenuController::ExitType exit_type) {
+ ui::ScopedXI2Event key_event;
+ key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
+ event_source_.Dispatch(key_event);
+ EXPECT_EQ(exit_type, controller_->exit_type());
+ controller_->exit_type_ = MenuController::EXIT_ALL;
+ DispatchEvent();
+ }
+#endif
+
+ void DispatchEvent() {
+#if defined(USE_X11)
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(xevent));
+ event_source_.Dispatch(&xevent);
+#elif defined(OS_WIN)
+ MSG msg;
+ memset(&msg, 0, sizeof(MSG));
+ dispatcher_client_.dispatcher()->Dispatch(msg);
+#elif defined(USE_OZONE)
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, true);
+ dispatcher_client_.dispatcher()->Dispatch(&event);
+#else
+#error Unsupported platform
+#endif
+ }
+
+ private:
+ void ResetMenuController() {
+ if (controller_) {
+ // These properties are faked by RunMenu for the purposes of testing and
+ // need to be undone before we call the destructor.
+ controller_->owner_ = NULL;
+ controller_->showing_ = false;
+ delete controller_;
+ controller_ = NULL;
+ }
+ }
+
+ // A weak pointer to the MenuController owned by this class.
+ MenuController* controller_;
+ scoped_ptr<base::RunLoop> run_loop_;
+ TestPlatformEventSource event_source_;
+ TestDispatcherClient dispatcher_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
+};
+
+TEST_F(MenuControllerTest, Basic) {
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(
+ base::MessageLoop::current());
+ message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this)));
+}
+
+#if defined(OS_LINUX) && defined(USE_X11)
+// Tests that an event targeter which blocks events will be honored by the menu
+// event dispatcher.
+TEST_F(MenuControllerTest, EventTargeter) {
+ {
+ // Verify that the menu handles the escape key under normal circumstances.
+ scoped_ptr<Widget> owner(CreateOwnerWidget());
+ message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
+ base::Unretained(this),
+ MenuController::EXIT_OUTERMOST));
+ RunMenu(owner.get());
+ }
+
+ {
+ // With the NULL targeter instantiated and assigned we expect the menu to
+ // not handle the key event.
+ scoped_ptr<Widget> owner(CreateOwnerWidget());
+ aura::ScopedWindowTargeter scoped_targeter(
+ owner->GetNativeWindow()->GetRootWindow(),
+ scoped_ptr<ui::EventTargeter>(new TestNullTargeter));
+ message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
+ base::Unretained(this),
+ MenuController::EXIT_NONE));
+ RunMenu(owner.get());
+ }
+}
+#endif
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller_win.cc b/chromium/ui/views/controls/menu/menu_controller_win.cc
deleted file mode 100644
index bbf7e9b1366..00000000000
--- a/chromium/ui/views/controls/menu/menu_controller_win.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/menu/menu_controller.h"
-
-#include "base/run_loop.h"
-#include "ui/gfx/screen.h"
-
-namespace views {
-
-void MenuController::RunMessageLoop(bool nested_menu) {
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoop::ScopedNestableTaskAllower allow(loop);
- base::RunLoop run_loop(this);
- run_loop.Run();
-}
-
-bool MenuController::ShouldQuitNow() const {
- return true;
-}
-
-gfx::Screen* MenuController::GetScreen() {
- return gfx::Screen::GetNativeScreen();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_delegate.cc b/chromium/ui/views/controls/menu/menu_delegate.cc
index 90ab5cbe1b2..6778545f415 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.cc
+++ b/chromium/ui/views/controls/menu/menu_delegate.cc
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/events/event.h"
+#include "ui/views/controls/menu/menu_config.h"
+
namespace views {
MenuDelegate::~MenuDelegate() {}
@@ -13,14 +15,19 @@ bool MenuDelegate::IsItemChecked(int id) const {
return false;
}
-string16 MenuDelegate::GetLabel(int id) const {
- return string16();
+base::string16 MenuDelegate::GetLabel(int id) const {
+ return base::string16();
}
-const gfx::Font* MenuDelegate::GetLabelFont(int id) const {
+const gfx::FontList* MenuDelegate::GetLabelFontList(int id) const {
return NULL;
}
+bool MenuDelegate::GetShouldUseDisabledEmphasizedForegroundColor(
+ int command_id) const {
+ return false;
+}
+
bool MenuDelegate::GetBackgroundColor(int command_id,
bool is_hovered,
SkColor* override_color) const {
@@ -33,12 +40,12 @@ bool MenuDelegate::GetForegroundColor(int command_id,
return false;
}
-string16 MenuDelegate::GetTooltipText(int id,
+base::string16 MenuDelegate::GetTooltipText(int id,
const gfx::Point& screen_loc) const {
- return string16();
+ return base::string16();
}
-bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) {
+bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) const {
return false;
}
@@ -57,7 +64,11 @@ bool MenuDelegate::IsCommandEnabled(int id) const {
return true;
}
-bool MenuDelegate::GetContextualLabel(int id, string16* out) const {
+bool MenuDelegate::IsCommandVisible(int id) const {
+ return true;
+}
+
+bool MenuDelegate::GetContextualLabel(int id, base::string16* out) const {
return false;
}
@@ -126,7 +137,7 @@ int MenuDelegate::GetDragOperations(MenuItemView* sender) {
MenuItemView* MenuDelegate::GetSiblingMenu(MenuItemView* menu,
const gfx::Point& screen_point,
- MenuItemView::AnchorPosition* anchor,
+ MenuAnchorPosition* anchor,
bool* has_mnemonics,
MenuButton** button) {
return NULL;
diff --git a/chromium/ui/views/controls/menu/menu_delegate.h b/chromium/ui/views/controls/menu/menu_delegate.h
index f171d570b7e..fafccd790f9 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.h
+++ b/chromium/ui/views/controls/menu/menu_delegate.h
@@ -10,23 +10,29 @@
#include "base/logging.h"
#include "base/strings/string16.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/menu/menu_types.h"
+#include "ui/views/views_export.h"
using ui::OSExchangeData;
namespace gfx {
-class Font;
+class FontList;
+class Point;
}
namespace ui {
class Accelerator;
+class DropTargetEvent;
}
namespace views {
class MenuButton;
+class MenuItemView;
// MenuDelegate --------------------------------------------------------------
@@ -61,14 +67,21 @@ class VIEWS_EXPORT MenuDelegate {
// The string shown for the menu item. This is only invoked when an item is
// added with an empty label.
- virtual string16 GetLabel(int id) const;
+ virtual base::string16 GetLabel(int id) const;
// The font for the menu item label.
- virtual const gfx::Font* GetLabelFont(int id) const;
+ virtual const gfx::FontList* GetLabelFontList(int id) const;
+
+ // Whether this item should be displayed with a bolder color when disabled.
+ virtual bool GetShouldUseDisabledEmphasizedForegroundColor(
+ int command_id) const;
// Override the text color of a given menu item dependent on the
// |command_id| and its |is_hovered| state. Returns true if it chooses to
// override the color.
+ //
+ // TODO(erg): Remove this interface. Injecting raw colors into the menu
+ // circumvents the NativeTheme.
virtual bool GetForegroundColor(int command_id,
bool is_hovered,
SkColor* override_color) const;
@@ -76,17 +89,21 @@ class VIEWS_EXPORT MenuDelegate {
// Override the background color of a given menu item dependent on the
// |command_id| and its |is_hovered| state. Returns true if it chooses to
// override the color.
+ //
+ // TODO(erg): Remove this interface. Injecting raw colors into the menu
+ // circumvents the NativeTheme.
virtual bool GetBackgroundColor(int command_id,
bool is_hovered,
SkColor* override_color) const;
// The tooltip shown for the menu item. This is invoked when the user
// hovers over the item, and no tooltip text has been set for that item.
- virtual string16 GetTooltipText(int id, const gfx::Point& screen_loc) const;
+ virtual base::string16 GetTooltipText(int id,
+ const gfx::Point& screen_loc) const;
// If there is an accelerator for the menu item with id |id| it is set in
// |accelerator| and true is returned.
- virtual bool GetAccelerator(int id, ui::Accelerator* accelerator);
+ virtual bool GetAccelerator(int id, ui::Accelerator* accelerator) const;
// Shows the context menu with the specified id. This is invoked when the
// user does the appropriate gesture to show a context menu. The id
@@ -104,7 +121,8 @@ class VIEWS_EXPORT MenuDelegate {
// Controller
virtual bool SupportsCommand(int id) const;
virtual bool IsCommandEnabled(int id) const;
- virtual bool GetContextualLabel(int id, string16* out) const;
+ virtual bool IsCommandVisible(int id) const;
+ virtual bool GetContextualLabel(int id, base::string16* out) const;
virtual void ExecuteCommand(int id) {
}
@@ -202,7 +220,7 @@ class VIEWS_EXPORT MenuDelegate {
// The delegate owns the returned menu, not the controller.
virtual MenuItemView* GetSiblingMenu(MenuItemView* menu,
const gfx::Point& screen_point,
- MenuItemView::AnchorPosition* anchor,
+ MenuAnchorPosition* anchor,
bool* has_mnemonics,
MenuButton** button);
diff --git a/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.cc b/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.cc
new file mode 100644
index 00000000000..181ba241afe
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.cc
@@ -0,0 +1,91 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_event_dispatcher_linux.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace internal {
+
+MenuEventDispatcher::MenuEventDispatcher(MenuController* controller)
+ : menu_controller_(controller) {}
+
+MenuEventDispatcher::~MenuEventDispatcher() {}
+
+bool MenuEventDispatcher::CanDispatchEvent(const ui::PlatformEvent& event) {
+ return true;
+}
+
+uint32_t MenuEventDispatcher::DispatchEvent(const ui::PlatformEvent& event) {
+ bool should_quit = false;
+ bool should_perform_default = true;
+ bool should_process_event = true;
+
+ // Check if the event should be handled.
+ scoped_ptr<ui::Event> ui_event(ui::EventFromNative(event));
+ if (ui_event && menu_controller_->owner()) {
+ aura::Window* menu_window = menu_controller_->owner()->GetNativeWindow();
+ aura::Window* target_window = static_cast<aura::Window*>(
+ static_cast<ui::EventTarget*>(menu_window->GetRootWindow())->
+ GetEventTargeter()->FindTargetForEvent(menu_window,
+ ui_event.get()));
+ // TODO(flackr): The event shouldn't be handled if target_window is not
+ // menu_window, however the event targeter does not properly target the
+ // open menu. For now, we allow targeters to prevent handling by the menu.
+ if (!target_window)
+ should_process_event = false;
+ }
+
+ if (menu_controller_->exit_type() == MenuController::EXIT_ALL ||
+ menu_controller_->exit_type() == MenuController::EXIT_DESTROYED) {
+ should_quit = true;
+ } else if (should_process_event) {
+ switch (ui::EventTypeFromNative(event)) {
+ case ui::ET_KEY_PRESSED: {
+ if (!menu_controller_->OnKeyDown(ui::KeyboardCodeFromNative(event))) {
+ should_quit = true;
+ should_perform_default = false;
+ break;
+ }
+
+ // Do not check mnemonics if the Alt or Ctrl modifiers are pressed.
+ int flags = ui::EventFlagsFromNative(event);
+ if ((flags & (ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) == 0) {
+ char c = ui::GetCharacterFromKeyCode(
+ ui::KeyboardCodeFromNative(event), flags);
+ if (menu_controller_->SelectByChar(c)) {
+ should_quit = true;
+ should_perform_default = false;
+ break;
+ }
+ }
+ should_quit = false;
+ should_perform_default = false;
+ break;
+ }
+ case ui::ET_KEY_RELEASED:
+ should_quit = false;
+ should_perform_default = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (should_quit || menu_controller_->exit_type() != MenuController::EXIT_NONE)
+ menu_controller_->TerminateNestedMessageLoop();
+
+ return should_perform_default ? ui::POST_DISPATCH_PERFORM_DEFAULT
+ : ui::POST_DISPATCH_NONE;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.h b/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.h
new file mode 100644
index 00000000000..bdc76fd88ba
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/macros.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+
+namespace views {
+
+class MenuController;
+
+namespace internal {
+
+// A message-pump dispatcher object used to dispatch events from the nested
+// message-loop initiated by the MenuController.
+class MenuEventDispatcher : public ui::PlatformEventDispatcher {
+ public:
+ explicit MenuEventDispatcher(MenuController* menu_controller);
+ virtual ~MenuEventDispatcher();
+
+ private:
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+
+ MenuController* menu_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuEventDispatcher);
+};
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index 4645e1ba6aa..2716ec8bb78 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -18,10 +18,6 @@
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/views/corewm/shadow_types.h"
-#endif
-
namespace views {
////////////////////////////////////////////////////////////////////////////////
@@ -49,7 +45,8 @@ void MenuHost::InitMenuHost(Widget* parent,
bool rounded_border = menu_controller && menu_config.corner_radius > 0;
bool bubble_border = submenu_->GetScrollViewContainer() &&
submenu_->GetScrollViewContainer()->HasBubbleBorder();
- params.has_dropshadow = !bubble_border;
+ params.shadow_type = bubble_border ? Widget::InitParams::SHADOW_TYPE_NONE
+ : Widget::InitParams::SHADOW_TYPE_DROP;
params.opacity = (bubble_border || rounded_border) ?
Widget::InitParams::TRANSLUCENT_WINDOW :
Widget::InitParams::OPAQUE_WINDOW;
@@ -57,14 +54,7 @@ void MenuHost::InitMenuHost(Widget* parent,
params.bounds = bounds;
Init(params);
-#if defined(USE_AURA)
- if (bubble_border)
- SetShadowType(GetNativeView(), views::corewm::SHADOW_TYPE_NONE);
-#endif
-
SetContentsView(contents_view);
- if (bubble_border || rounded_border)
- SetOpacity(0);
ShowMenuHost(do_capture);
}
@@ -76,13 +66,11 @@ void MenuHost::ShowMenuHost(bool do_capture) {
// Doing a capture may make us get capture lost. Ignore it while we're in the
// process of showing.
base::AutoReset<bool> reseter(&ignore_capture_lost_, true);
- Show();
+ ShowInactive();
if (do_capture) {
-#if defined(USE_AURA)
// Cancel existing touches, so we don't miss some touch release/cancel
// events due to the menu taking capture.
- ui::GestureRecognizer::Get()->TransferEventsTo(GetNativeWindow(), NULL);
-#endif // USE_AURA
+ ui::GestureRecognizer::Get()->TransferEventsTo(NULL, NULL);
native_widget_private()->SetCapture();
}
}
diff --git a/chromium/ui/views/controls/menu/menu_host_root_view.cc b/chromium/ui/views/controls/menu/menu_host_root_view.cc
index 2577d909b7b..3bce4a49b6e 100644
--- a/chromium/ui/views/controls/menu/menu_host_root_view.cc
+++ b/chromium/ui/views/controls/menu/menu_host_root_view.cc
@@ -51,17 +51,8 @@ void MenuHostRootView::OnMouseMoved(const ui::MouseEvent& event) {
}
bool MenuHostRootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
-#if defined(USE_AURA)
- // Aura uses MenuController to forward events like other mouse events.
return GetMenuController() &&
GetMenuController()->OnMouseWheel(submenu_, event);
-#else
- // Windows uses focus_util_win::RerouteMouseWheel to forward events to
- // the right menu.
- // RootView::OnMouseWheel forwards to the focused view. We don't have a
- // focused view, so we need to override this then forward to the menu.
- return submenu_->OnMouseWheel(event);
-#endif
}
void MenuHostRootView::DispatchGestureEvent(ui::GestureEvent* event) {
diff --git a/chromium/ui/views/controls/menu/menu_image_util.cc b/chromium/ui/views/controls/menu/menu_image_util.cc
index a50980b3500..60315736fe2 100644
--- a/chromium/ui/views/controls/menu/menu_image_util.cc
+++ b/chromium/ui/views/controls/menu/menu_image_util.cc
@@ -54,7 +54,7 @@ class RadioButtonImageSource : public gfx::CanvasImageSource {
skia::RefPtr<SkShader> shader = skia::AdoptRef(
SkGradientShader::CreateLinear(
gradient_points, gradient_colors, NULL, arraysize(gradient_points),
- SkShader::kClamp_TileMode, NULL));
+ SkShader::kClamp_TileMode));
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setAntiAlias(true);
@@ -76,8 +76,7 @@ class RadioButtonImageSource : public gfx::CanvasImageSource {
shader = skia::AdoptRef(
SkGradientShader::CreateLinear(
selected_gradient_points, selected_gradient_colors, NULL,
- arraysize(selected_gradient_points),
- SkShader::kClamp_TileMode, NULL));
+ arraysize(selected_gradient_points), SkShader::kClamp_TileMode));
paint.setShader(shader.get());
paint.setStyle(SkPaint::kFill_Style);
canvas->sk_canvas()->drawCircle(radius, radius,
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 2adc1ad2f17..f24c61059c6 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -9,12 +9,15 @@
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/image/image.h"
+#include "ui/gfx/text_utils.h"
#include "ui/native_theme/common_theme.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/controls/image_view.h"
@@ -47,7 +50,7 @@ class EmptyMenuMenuItem : public MenuItemView {
}
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE {
+ base::string16* tooltip) const OVERRIDE {
// Empty menu items shouldn't have a tooltip.
return false;
}
@@ -116,7 +119,7 @@ void MenuItemView::ChildPreferredSizeChanged(View* child) {
}
bool MenuItemView::GetTooltipText(const gfx::Point& p,
- string16* tooltip) const {
+ base::string16* tooltip) const {
*tooltip = tooltip_;
if (!tooltip->empty())
return true;
@@ -147,15 +150,15 @@ bool MenuItemView::GetTooltipText(const gfx::Point& p,
return !tooltip->empty();
}
-void MenuItemView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_MENUITEM;
+void MenuItemView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_MENU_ITEM;
- string16 item_text;
+ base::string16 item_text;
if (IsContainer()) {
// The first child is taking over, just use its accessible name instead of
// |title_|.
View* child = child_at(0);
- ui::AccessibleViewState state;
+ ui::AXViewState state;
child->GetAccessibleState(&state);
item_text = state.name;
} else {
@@ -165,12 +168,12 @@ void MenuItemView::GetAccessibleState(ui::AccessibleViewState* state) {
switch (GetType()) {
case SUBMENU:
- state->state |= ui::AccessibilityTypes::STATE_HASPOPUP;
+ state->AddStateFlag(ui::AX_STATE_HASPOPUP);
break;
case CHECKBOX:
case RADIO:
- state->state |= GetDelegate()->IsItemChecked(GetCommand()) ?
- ui::AccessibilityTypes::STATE_CHECKED : 0;
+ if (GetDelegate()->IsItemChecked(GetCommand()))
+ state->AddStateFlag(ui::AX_STATE_CHECKED);
break;
case NORMAL:
case SEPARATOR:
@@ -181,22 +184,22 @@ void MenuItemView::GetAccessibleState(ui::AccessibleViewState* state) {
}
// static
-bool MenuItemView::IsBubble(MenuItemView::AnchorPosition anchor) {
- return anchor == MenuItemView::BUBBLE_LEFT ||
- anchor == MenuItemView::BUBBLE_RIGHT ||
- anchor == MenuItemView::BUBBLE_ABOVE ||
- anchor == MenuItemView::BUBBLE_BELOW;
+bool MenuItemView::IsBubble(MenuAnchorPosition anchor) {
+ return anchor == MENU_ANCHOR_BUBBLE_LEFT ||
+ anchor == MENU_ANCHOR_BUBBLE_RIGHT ||
+ anchor == MENU_ANCHOR_BUBBLE_ABOVE ||
+ anchor == MENU_ANCHOR_BUBBLE_BELOW;
}
// static
-string16 MenuItemView::GetAccessibleNameForMenuItem(
- const string16& item_text, const string16& minor_text) {
- string16 accessible_name = item_text;
+base::string16 MenuItemView::GetAccessibleNameForMenuItem(
+ const base::string16& item_text, const base::string16& minor_text) {
+ base::string16 accessible_name = item_text;
// Filter out the "&" for accessibility clients.
size_t index = 0;
- const char16 amp = '&';
- while ((index = accessible_name.find(amp, index)) != string16::npos &&
+ const base::char16 amp = '&';
+ while ((index = accessible_name.find(amp, index)) != base::string16::npos &&
index + 1 < accessible_name.length()) {
accessible_name.replace(index, accessible_name.length() - index,
accessible_name.substr(index + 1));
@@ -225,9 +228,9 @@ void MenuItemView::Cancel() {
MenuItemView* MenuItemView::AddMenuItemAt(
int index,
int item_id,
- const string16& label,
- const string16& sublabel,
- const string16& minor_text,
+ const base::string16& label,
+ const base::string16& sublabel,
+ const base::string16& minor_text,
const gfx::ImageSkia& icon,
Type type,
ui::MenuSeparatorType separator_style) {
@@ -251,6 +254,8 @@ MenuItemView* MenuItemView::AddMenuItemAt(
item->SetIcon(icon);
if (type == SUBMENU)
item->CreateSubmenu();
+ if (GetDelegate() && !GetDelegate()->IsCommandVisible(item_id))
+ item->SetVisible(false);
submenu_->AddChildViewAt(item, index);
return item;
}
@@ -271,51 +276,52 @@ void MenuItemView::RemoveMenuItemAt(int index) {
}
MenuItemView* MenuItemView::AppendMenuItem(int item_id,
- const string16& label,
+ const base::string16& label,
Type type) {
- return AppendMenuItemImpl(item_id, label, string16(), string16(),
+ return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(),
gfx::ImageSkia(), type, ui::NORMAL_SEPARATOR);
}
MenuItemView* MenuItemView::AppendSubMenu(int item_id,
- const string16& label) {
- return AppendMenuItemImpl(item_id, label, string16(), string16(),
+ const base::string16& label) {
+ return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(),
gfx::ImageSkia(), SUBMENU, ui::NORMAL_SEPARATOR);
}
MenuItemView* MenuItemView::AppendSubMenuWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
- return AppendMenuItemImpl(item_id, label, string16(), string16(), icon,
- SUBMENU, ui::NORMAL_SEPARATOR);
+ return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(),
+ icon, SUBMENU, ui::NORMAL_SEPARATOR);
}
-MenuItemView* MenuItemView::AppendMenuItemWithLabel(int item_id,
- const string16& label) {
+MenuItemView* MenuItemView::AppendMenuItemWithLabel(
+ int item_id,
+ const base::string16& label) {
return AppendMenuItem(item_id, label, NORMAL);
}
MenuItemView* MenuItemView::AppendDelegateMenuItem(int item_id) {
- return AppendMenuItem(item_id, string16(), NORMAL);
+ return AppendMenuItem(item_id, base::string16(), NORMAL);
}
void MenuItemView::AppendSeparator() {
- AppendMenuItemImpl(0, string16(), string16(), string16(), gfx::ImageSkia(),
- SEPARATOR, ui::NORMAL_SEPARATOR);
+ AppendMenuItemImpl(0, base::string16(), base::string16(), base::string16(),
+ gfx::ImageSkia(), SEPARATOR, ui::NORMAL_SEPARATOR);
}
MenuItemView* MenuItemView::AppendMenuItemWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
- return AppendMenuItemImpl(item_id, label, string16(), string16(), icon,
- NORMAL, ui::NORMAL_SEPARATOR);
+ return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(),
+ icon, NORMAL, ui::NORMAL_SEPARATOR);
}
MenuItemView* MenuItemView::AppendMenuItemImpl(
int item_id,
- const string16& label,
- const string16& sublabel,
- const string16& minor_text,
+ const base::string16& label,
+ const base::string16& sublabel,
+ const base::string16& minor_text,
const gfx::ImageSkia& icon,
Type type,
ui::MenuSeparatorType separator_style) {
@@ -338,17 +344,17 @@ SubmenuView* MenuItemView::GetSubmenu() const {
return submenu_;
}
-void MenuItemView::SetTitle(const string16& title) {
+void MenuItemView::SetTitle(const base::string16& title) {
title_ = title;
invalidate_dimensions(); // Triggers preferred size recalculation.
}
-void MenuItemView::SetSubtitle(const string16& subtitle) {
+void MenuItemView::SetSubtitle(const base::string16& subtitle) {
subtitle_ = subtitle;
invalidate_dimensions(); // Triggers preferred size recalculation.
}
-void MenuItemView::SetMinorText(const string16& minor_text) {
+void MenuItemView::SetMinorText(const base::string16& minor_text) {
minor_text_ = minor_text;
invalidate_dimensions(); // Triggers preferred size recalculation.
}
@@ -358,7 +364,7 @@ void MenuItemView::SetSelected(bool selected) {
SchedulePaint();
}
-void MenuItemView::SetTooltip(const string16& tooltip, int item_id) {
+void MenuItemView::SetTooltip(const base::string16& tooltip, int item_id) {
MenuItemView* item = GetMenuItemByID(item_id);
DCHECK(item);
item->tooltip_ = tooltip;
@@ -399,13 +405,13 @@ void MenuItemView::OnPaint(gfx::Canvas* canvas) {
PaintButton(canvas, PB_NORMAL);
}
-gfx::Size MenuItemView::GetPreferredSize() {
+gfx::Size MenuItemView::GetPreferredSize() const {
const MenuItemDimensions& dimensions(GetDimensions());
return gfx::Size(dimensions.standard_width + dimensions.children_width,
dimensions.height);
}
-const MenuItemView::MenuItemDimensions& MenuItemView::GetDimensions() {
+const MenuItemView::MenuItemDimensions& MenuItemView::GetDimensions() const {
if (!is_dimensions_valid())
dimensions_ = CalculateDimensions();
DCHECK(is_dimensions_valid());
@@ -441,16 +447,16 @@ const MenuItemView* MenuItemView::GetRootMenuItem() const {
return item;
}
-char16 MenuItemView::GetMnemonic() {
+base::char16 MenuItemView::GetMnemonic() {
if (!GetRootMenuItem()->has_mnemonics_)
return 0;
size_t index = 0;
do {
index = title_.find('&', index);
- if (index != string16::npos) {
+ if (index != base::string16::npos) {
if (index + 1 != title_.size() && title_[index + 1] != '&') {
- char16 char_array[] = { title_[index + 1], 0 };
+ base::char16 char_array[] = { title_[index + 1], 0 };
// TODO(jshin): What about Turkish locale? See http://crbug.com/81719.
// If the mnemonic is capital I and the UI language is Turkish,
// lowercasing it results in 'small dotless i', which is different
@@ -459,7 +465,7 @@ char16 MenuItemView::GetMnemonic() {
}
index++;
}
- } while (index != string16::npos);
+ } while (index != base::string16::npos);
return 0;
}
@@ -685,14 +691,14 @@ int MenuItemView::GetDrawStringFlags() {
return flags;
}
-const gfx::Font& MenuItemView::GetFont() {
+const gfx::FontList& MenuItemView::GetFontList() const {
const MenuDelegate* delegate = GetDelegate();
if (delegate) {
- const gfx::Font* font = delegate->GetLabelFont(GetCommand());
- if (font)
- return *font;
+ const gfx::FontList* font_list = delegate->GetLabelFontList(GetCommand());
+ if (font_list)
+ return *font_list;
}
- return GetMenuConfig().font;
+ return GetMenuConfig().font_list;
}
void MenuItemView::AddEmptyMenus() {
@@ -738,13 +744,6 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
parent_menu_item_->GetSubmenu()->GetShowSelection(this) &&
(NonIconChildViewsCount() == 0));
- int icon_x = config.item_left_margin + left_icon_margin_;
- int top_margin = GetTopMargin();
- int bottom_margin = GetBottomMargin();
- int icon_y = top_margin + (height() - config.item_top_margin -
- bottom_margin - config.check_height) / 2;
- int icon_height = config.check_height;
- int available_height = height() - top_margin - bottom_margin;
MenuDelegate *delegate = GetDelegate();
// Render the background. As MenuScrollViewContainer draws the background, we
// only need the background when we want it to look different, as when we're
@@ -766,21 +765,27 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
ui::NativeTheme::ExtraParams());
}
+ const int icon_x = config.item_left_margin + left_icon_margin_;
+ const int top_margin = GetTopMargin();
+ const int bottom_margin = GetBottomMargin();
+ const int available_height = height() - top_margin - bottom_margin;
+
// Render the check.
if (type_ == CHECKBOX && delegate->IsItemChecked(GetCommand())) {
- gfx::ImageSkia check = GetMenuCheckImage(IsSelected());
+ gfx::ImageSkia check = GetMenuCheckImage(render_selection);
// Don't use config.check_width here as it's padded
// to force more padding (AURA).
- gfx::Rect check_bounds(icon_x, icon_y, check.width(), icon_height);
+ gfx::Rect check_bounds(icon_x,
+ top_margin + (available_height - check.height()) / 2,
+ check.width(),
+ check.height());
AdjustBoundsForRTLUI(&check_bounds);
canvas->DrawImageInt(check, check_bounds.x(), check_bounds.y());
} else if (type_ == RADIO) {
gfx::ImageSkia image =
GetRadioButtonImage(delegate->IsItemChecked(GetCommand()));
gfx::Rect radio_bounds(icon_x,
- top_margin +
- (height() - top_margin - bottom_margin -
- image.height()) / 2,
+ top_margin + (available_height - image.height()) / 2,
image.width(),
image.height());
AdjustBoundsForRTLUI(&radio_bounds);
@@ -788,12 +793,18 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
}
// Render the foreground.
- ui::NativeTheme::ColorId color_id =
- ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor;
+ ui::NativeTheme::ColorId color_id;
if (enabled()) {
color_id = render_selection ?
ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor:
ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor;
+ } else {
+ bool emphasized = delegate &&
+ delegate->GetShouldUseDisabledEmphasizedForegroundColor(
+ GetCommand());
+ color_id = emphasized ?
+ ui::NativeTheme::kColorId_DisabledEmphasizedMenuItemForegroundColor :
+ ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor;
}
SkColor fg_color = native_theme->GetSystemColor(color_id);
SkColor override_foreground_color;
@@ -802,7 +813,7 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
&override_foreground_color))
fg_color = override_foreground_color;
- const gfx::Font& font = GetFont();
+ const gfx::FontList& font_list = GetFontList();
int accel_width = parent_menu_item_->GetSubmenu()->max_minor_text_width();
int label_start = GetLabelStartForThisItem();
@@ -817,19 +828,15 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
int flags = GetDrawStringFlags();
if (mode == PB_FOR_DRAG)
flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
- canvas->DrawStringInt(title(), font, fg_color,
- text_bounds.x(), text_bounds.y(), text_bounds.width(),
- text_bounds.height(), flags);
+ canvas->DrawStringRectWithFlags(title(), font_list, fg_color, text_bounds,
+ flags);
if (!subtitle_.empty()) {
- canvas->DrawStringInt(
+ canvas->DrawStringRectWithFlags(
subtitle_,
- font,
+ font_list,
GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_ButtonDisabledColor),
- text_bounds.x(),
- text_bounds.y() + GetFont().GetHeight(),
- text_bounds.width(),
- text_bounds.height(),
+ text_bounds + gfx::Vector2d(0, font_list.GetHeight()),
flags);
}
@@ -837,24 +844,23 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
// Render the submenu indicator (arrow).
if (HasSubmenu()) {
+ gfx::ImageSkia arrow = GetSubmenuArrowImage(render_selection);
gfx::Rect arrow_bounds(this->width() - config.arrow_width -
config.arrow_to_edge_padding,
- top_margin + (available_height -
- config.arrow_width) / 2,
- config.arrow_width, height());
+ top_margin + (available_height - arrow.height()) / 2,
+ config.arrow_width,
+ arrow.height());
AdjustBoundsForRTLUI(&arrow_bounds);
- canvas->DrawImageInt(GetSubmenuArrowImage(IsSelected()),
- arrow_bounds.x(), arrow_bounds.y());
+ canvas->DrawImageInt(arrow, arrow_bounds.x(), arrow_bounds.y());
}
}
void MenuItemView::PaintMinorText(gfx::Canvas* canvas,
bool render_selection) {
- string16 minor_text = GetMinorText();
+ base::string16 minor_text = GetMinorText();
if (minor_text.empty())
return;
- const gfx::Font& font = GetFont();
int available_height = height() - GetTopMargin() - GetBottomMargin();
int max_accel_width =
parent_menu_item_->GetSubmenu()->max_minor_text_width();
@@ -870,16 +876,13 @@ void MenuItemView::PaintMinorText(gfx::Canvas* canvas,
flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
else
flags |= gfx::Canvas::TEXT_ALIGN_RIGHT;
- canvas->DrawStringInt(
+ canvas->DrawStringRectWithFlags(
minor_text,
- font,
+ GetFontList(),
GetNativeTheme()->GetSystemColor(render_selection ?
ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor :
ui::NativeTheme::kColorId_ButtonDisabledColor),
- accel_bounds.x(),
- accel_bounds.y(),
- accel_bounds.width(),
- accel_bounds.height(),
+ accel_bounds,
flags);
}
@@ -894,38 +897,36 @@ void MenuItemView::DestroyAllMenuHosts() {
}
}
-int MenuItemView::GetTopMargin() {
+int MenuItemView::GetTopMargin() const {
if (top_margin_ >= 0)
return top_margin_;
- MenuItemView* root = GetRootMenuItem();
+ const MenuItemView* root = GetRootMenuItem();
return root && root->has_icons_
? GetMenuConfig().item_top_margin :
GetMenuConfig().item_no_icon_top_margin;
}
-int MenuItemView::GetBottomMargin() {
+int MenuItemView::GetBottomMargin() const {
if (bottom_margin_ >= 0)
return bottom_margin_;
- MenuItemView* root = GetRootMenuItem();
+ const MenuItemView* root = GetRootMenuItem();
return root && root->has_icons_
? GetMenuConfig().item_bottom_margin :
GetMenuConfig().item_no_icon_bottom_margin;
}
-gfx::Size MenuItemView::GetChildPreferredSize() {
+gfx::Size MenuItemView::GetChildPreferredSize() const {
if (!has_children())
return gfx::Size();
- if (IsContainer()) {
- View* child = child_at(0);
- return child->GetPreferredSize();
- }
+ if (IsContainer())
+ return child_at(0)->GetPreferredSize();
int width = 0;
for (int i = 0; i < child_count(); ++i) {
- View* child = child_at(i);
+ const View* child = child_at(i);
if (icon_view_ && (icon_view_ == child))
continue;
if (i)
@@ -941,7 +942,7 @@ gfx::Size MenuItemView::GetChildPreferredSize() {
return gfx::Size(width, height);
}
-MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() {
+MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
gfx::Size child_size = GetChildPreferredSize();
MenuItemDimensions dimensions;
@@ -961,7 +962,7 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() {
return dimensions;
// Determine the length of the label text.
- const gfx::Font& font = GetFont();
+ const gfx::FontList& font_list = GetFontList();
// Get Icon margin overrides for this particular item.
const MenuDelegate* delegate = GetDelegate();
@@ -976,27 +977,30 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() {
}
int label_start = GetLabelStartForThisItem();
- int string_width = font.GetStringWidth(title_);
- if (!subtitle_.empty())
- string_width = std::max(string_width, font.GetStringWidth(subtitle_));
+ int string_width = gfx::GetStringWidth(title_, font_list);
+ if (!subtitle_.empty()) {
+ string_width = std::max(string_width,
+ gfx::GetStringWidth(subtitle_, font_list));
+ }
dimensions.standard_width = string_width + label_start +
item_right_margin_;
// Determine the length of the right-side text.
- string16 minor_text = GetMinorText();
+ base::string16 minor_text = GetMinorText();
dimensions.minor_text_width =
- minor_text.empty() ? 0 : GetFont().GetStringWidth(minor_text);
+ minor_text.empty() ? 0 : gfx::GetStringWidth(minor_text, font_list);
// Determine the height to use.
+ dimensions.height =
+ std::max(dimensions.height,
+ (subtitle_.empty() ? 0 : font_list.GetHeight()) +
+ font_list.GetHeight() + GetBottomMargin() + GetTopMargin());
dimensions.height = std::max(dimensions.height,
- (subtitle_.empty() ? 0 : font.GetHeight()) +
- font.GetHeight() + GetBottomMargin() + GetTopMargin());
- dimensions.height = std::max(dimensions.height,
- GetMenuConfig().item_min_height);
+ GetMenuConfig().item_min_height);
return dimensions;
}
-int MenuItemView::GetLabelStartForThisItem() {
+int MenuItemView::GetLabelStartForThisItem() const {
int label_start = label_start_ + left_icon_margin_ + right_icon_margin_;
if ((type_ == CHECKBOX || type_ == RADIO) && icon_view_) {
label_start += icon_view_->size().width() +
@@ -1005,10 +1009,10 @@ int MenuItemView::GetLabelStartForThisItem() {
return label_start;
}
-string16 MenuItemView::GetMinorText() {
+base::string16 MenuItemView::GetMinorText() const {
if (id() == kEmptyMenuItemViewID) {
// Don't query the delegate for menus that represent no children.
- return string16();
+ return base::string16();
}
ui::Accelerator accelerator;
diff --git a/chromium/ui/views/controls/menu/menu_item_view.h b/chromium/ui/views/controls/menu/menu_item_view.h
index 2d394bae2f2..4f0ea441caa 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.h
+++ b/chromium/ui/views/controls/menu/menu_item_view.h
@@ -15,6 +15,7 @@
#include "ui/base/models/menu_separator_types.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/controls/menu/menu_config.h"
+#include "ui/views/controls/menu/menu_types.h"
#include "ui/views/view.h"
#if defined(OS_WIN)
@@ -24,7 +25,7 @@
#endif
namespace gfx {
-class Font;
+class FontList;
}
namespace views {
@@ -83,21 +84,6 @@ class VIEWS_EXPORT MenuItemView : public View {
EMPTY
};
- // Where the menu should be anchored to for non-RTL languages. The
- // opposite position will be used if base::i18n:IsRTL() is true.
- // The BUBBLE flags are used when the menu should get enclosed by a bubble.
- // Note that BUBBLE flags should only be used with menus which have no
- // children.
- enum AnchorPosition {
- TOPLEFT,
- TOPRIGHT,
- BOTTOMCENTER,
- BUBBLE_LEFT,
- BUBBLE_RIGHT,
- BUBBLE_ABOVE,
- BUBBLE_BELOW
- };
-
// Where the menu should be drawn, above or below the bounds (when
// the bounds is non-empty). POSITION_BEST_FIT (default) positions
// the menu below the bounds unless the menu does not fit on the
@@ -132,8 +118,8 @@ class VIEWS_EXPORT MenuItemView : public View {
// Overridden from View:
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// Returns the preferred height of menu items. This is only valid when the
// menu is about to be shown.
@@ -143,12 +129,12 @@ class VIEWS_EXPORT MenuItemView : public View {
static int label_start() { return label_start_; }
// Returns if a given |anchor| is a bubble or not.
- static bool IsBubble(MenuItemView::AnchorPosition anchor);
+ static bool IsBubble(MenuAnchorPosition anchor);
// Returns the accessible name to be used with screen readers. Mnemonics are
// removed and the menu item accelerator text is appended.
- static string16 GetAccessibleNameForMenuItem(
- const string16& item_text, const string16& accelerator_text);
+ static base::string16 GetAccessibleNameForMenuItem(
+ const base::string16& item_text, const base::string16& accelerator_text);
// Hides and cancels the menu. This does nothing if the menu is not open.
void Cancel();
@@ -157,9 +143,9 @@ class VIEWS_EXPORT MenuItemView : public View {
// called after adding menu items if the menu may be active.
MenuItemView* AddMenuItemAt(int index,
int item_id,
- const string16& label,
- const string16& sublabel,
- const string16& minor_text,
+ const base::string16& label,
+ const base::string16& sublabel,
+ const base::string16& minor_text,
const gfx::ImageSkia& icon,
Type type,
ui::MenuSeparatorType separator_style);
@@ -177,24 +163,24 @@ class VIEWS_EXPORT MenuItemView : public View {
// label The text label shown.
// type The type of item.
MenuItemView* AppendMenuItem(int item_id,
- const string16& label,
+ const base::string16& label,
Type type);
// Append a submenu to this menu.
// The returned pointer is owned by this menu.
MenuItemView* AppendSubMenu(int item_id,
- const string16& label);
+ const base::string16& label);
// Append a submenu with an icon to this menu.
// The returned pointer is owned by this menu.
MenuItemView* AppendSubMenuWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
// This is a convenience for standard text label menu items where the label
// is provided with this call.
MenuItemView* AppendMenuItemWithLabel(int item_id,
- const string16& label);
+ const base::string16& label);
// This is a convenience for text label menu items where the label is
// provided by the delegate.
@@ -207,14 +193,14 @@ class VIEWS_EXPORT MenuItemView : public View {
// needs an icon. Calling this function forces the Menu class to draw
// the menu, instead of relying on Windows.
MenuItemView* AppendMenuItemWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
// All the AppendXXX methods funnel into this.
MenuItemView* AppendMenuItemImpl(int item_id,
- const string16& label,
- const string16& sublabel,
- const string16& minor_text,
+ const base::string16& label,
+ const base::string16& sublabel,
+ const base::string16& minor_text,
const gfx::ImageSkia& icon,
Type type,
ui::MenuSeparatorType separator_style);
@@ -234,14 +220,14 @@ class VIEWS_EXPORT MenuItemView : public View {
const MenuItemView* GetParentMenuItem() const { return parent_menu_item_; }
// Sets/Gets the title.
- void SetTitle(const string16& title);
- const string16& title() const { return title_; }
+ void SetTitle(const base::string16& title);
+ const base::string16& title() const { return title_; }
// Sets the subtitle.
- void SetSubtitle(const string16& subtitle);
+ void SetSubtitle(const base::string16& subtitle);
// Sets the minor text.
- void SetMinorText(const string16& minor_text);
+ void SetMinorText(const base::string16& minor_text);
// Returns the type of this menu.
const Type& GetType() const { return type_; }
@@ -254,7 +240,7 @@ class VIEWS_EXPORT MenuItemView : public View {
bool IsSelected() const { return selected_; }
// Sets the |tooltip| for a menu item view with |item_id| identifier.
- void SetTooltip(const string16& tooltip, int item_id);
+ void SetTooltip(const base::string16& tooltip, int item_id);
// Sets the icon for the descendant identified by item_id.
void SetIcon(const gfx::ImageSkia& icon, int item_id);
@@ -277,10 +263,10 @@ class VIEWS_EXPORT MenuItemView : public View {
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
// Returns the preferred size of this item.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Return the preferred dimensions of the item in pixel.
- const MenuItemDimensions& GetDimensions();
+ const MenuItemDimensions& GetDimensions() const;
// Returns the object responsible for controlling showing the menu.
MenuController* GetMenuController();
@@ -297,7 +283,7 @@ class VIEWS_EXPORT MenuItemView : public View {
// Returns the mnemonic for this MenuItemView, or 0 if this MenuItemView
// doesn't have a mnemonic.
- char16 GetMnemonic();
+ base::char16 GetMnemonic();
// Do we have icons? This only has effect on the top menu. Turning this on
// makes the menus slightly wider and taller.
@@ -344,11 +330,11 @@ class VIEWS_EXPORT MenuItemView : public View {
virtual const char* GetClassName() const OVERRIDE;
// Returns the preferred size (and padding) of any children.
- virtual gfx::Size GetChildPreferredSize();
+ virtual gfx::Size GetChildPreferredSize() const;
// Returns the various margins.
- int GetTopMargin();
- int GetBottomMargin();
+ int GetTopMargin() const;
+ int GetBottomMargin() const;
private:
friend class internal::MenuRunnerImpl; // For access to ~MenuItemView.
@@ -372,11 +358,11 @@ class VIEWS_EXPORT MenuItemView : public View {
bool has_mnemonics,
bool show_mnemonics);
- // Returns the flags passed to DrawStringInt.
+ // Returns the flags passed to DrawStringRect.
int GetDrawStringFlags();
- // Returns the font to use for menu text.
- const gfx::Font& GetFont();
+ // Returns the font list to use for menu text.
+ const gfx::FontList& GetFontList() const;
// If this menu item has no children a child is added showing it has no
// children. Otherwise AddEmtpyMenus is recursively invoked on child menu
@@ -403,13 +389,13 @@ class VIEWS_EXPORT MenuItemView : public View {
// Returns the text that should be displayed on the end (right) of the menu
// item. This will be the accelerator (if one exists), otherwise |subtitle_|.
- string16 GetMinorText();
+ base::string16 GetMinorText() const;
// Calculates and returns the MenuItemDimensions.
- MenuItemDimensions CalculateDimensions();
+ MenuItemDimensions CalculateDimensions() const;
// Get the horizontal position at which to draw the menu item's label.
- int GetLabelStartForThisItem();
+ int GetLabelStartForThisItem() const;
// Used by MenuController to cache the menu position in use by the
// active menu.
@@ -464,13 +450,13 @@ class VIEWS_EXPORT MenuItemView : public View {
SubmenuView* submenu_;
// Title.
- string16 title_;
+ base::string16 title_;
// Subtitle/sublabel.
- string16 subtitle_;
+ base::string16 subtitle_;
// Minor text.
- string16 minor_text_;
+ base::string16 minor_text_;
// Does the title have a mnemonic? Only useful on the root menu item.
bool has_mnemonics_;
@@ -486,7 +472,7 @@ class VIEWS_EXPORT MenuItemView : public View {
View* icon_view_;
// The tooltip to show on hover for this menu item.
- string16 tooltip_;
+ base::string16 tooltip_;
// Width of a menu icon area.
static int icon_area_width_;
@@ -502,7 +488,7 @@ class VIEWS_EXPORT MenuItemView : public View {
// Cached dimensions. This is cached as text sizing calculations are quite
// costly.
- MenuItemDimensions dimensions_;
+ mutable MenuItemDimensions dimensions_;
// Removed items to be deleted in ChildrenChanged().
std::vector<View*> removed_items_;
@@ -513,8 +499,8 @@ class VIEWS_EXPORT MenuItemView : public View {
// Horizontal icon margins in pixels, which can differ between MenuItems.
// These values will be set in the layout process.
- int left_icon_margin_;
- int right_icon_margin_;
+ mutable int left_icon_margin_;
+ mutable int right_icon_margin_;
// |menu_position_| is the requested position with respect to the bounds.
// |actual_menu_position_| is used by the controller to cache the
diff --git a/chromium/ui/views/controls/menu/menu_message_loop.h b/chromium/ui/views/controls/menu/menu_message_loop.h
new file mode 100644
index 00000000000..a435d85f402
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop.h
@@ -0,0 +1,57 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_H_
+
+#include "ui/gfx/native_widget_types.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+class LocatedEvent;
+}
+
+namespace views {
+
+class MenuController;
+class Widget;
+
+// Interface used by MenuController to run a nested message loop while
+// showing a menu, allowing for platform specific implementations.
+class MenuMessageLoop {
+ public:
+ virtual ~MenuMessageLoop() {}
+
+ // Create a platform specific instance.
+ static MenuMessageLoop* Create();
+
+ // Runs the platform specific bits of the message loop. If |nested_menu| is
+ // true we're being asked to run a menu from within a menu (eg a context
+ // menu).
+ virtual void Run(MenuController*, Widget* owner, bool nested_menu) = 0;
+
+ // Returns true if it is a good time to call QuitNow().
+ // Returns false otherwise, for example if a drag and drop is in progress.
+ virtual bool ShouldQuitNow() const = 0;
+
+ // Quit an earlier call to Run().
+ virtual void QuitNow() = 0;
+
+ // Repost |event| to |window|.
+ // |screen_loc| is the event's location in screen coordinates.
+ virtual void RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) = 0;
+
+ // Clear any references to the owner widget that was passed into the previous
+ // call to Run().
+ virtual void ClearOwner() = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_H_
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_aura.cc b/chromium/ui/views/controls/menu/menu_message_loop_aura.cc
new file mode 100644
index 00000000000..0d7e99aab03
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop_aura.cc
@@ -0,0 +1,202 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_message_loop_aura.h"
+
+#if defined(OS_WIN)
+#include <windowsx.h>
+#endif
+
+#include "base/run_loop.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/public/activation_change_observer.h"
+#include "ui/wm/public/activation_client.h"
+#include "ui/wm/public/dispatcher_client.h"
+#include "ui/wm/public/drag_drop_client.h"
+
+#if defined(OS_WIN)
+#include "ui/base/win/internal_constants.h"
+#include "ui/views/controls/menu/menu_message_pump_dispatcher_win.h"
+#include "ui/views/win/hwnd_util.h"
+#else
+#include "ui/views/controls/menu/menu_event_dispatcher_linux.h"
+#endif
+
+using aura::client::ScreenPositionClient;
+
+namespace views {
+
+namespace {
+
+aura::Window* GetOwnerRootWindow(views::Widget* owner) {
+ return owner ? owner->GetNativeWindow()->GetRootWindow() : NULL;
+}
+
+// ActivationChangeObserverImpl is used to observe activation changes and close
+// the menu. Additionally it listens for the root window to be destroyed and
+// cancel the menu as well.
+class ActivationChangeObserverImpl
+ : public aura::client::ActivationChangeObserver,
+ public aura::WindowObserver,
+ public ui::EventHandler {
+ public:
+ ActivationChangeObserverImpl(MenuController* controller, aura::Window* root)
+ : controller_(controller), root_(root) {
+ aura::client::GetActivationClient(root_)->AddObserver(this);
+ root_->AddObserver(this);
+ root_->AddPreTargetHandler(this);
+ }
+
+ virtual ~ActivationChangeObserverImpl() { Cleanup(); }
+
+ // aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE {
+ if (!controller_->drag_in_progress())
+ controller_->CancelAll();
+ }
+
+ // aura::WindowObserver:
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { Cleanup(); }
+
+ // ui::EventHandler:
+ virtual void OnCancelMode(ui::CancelModeEvent* event) OVERRIDE {
+ controller_->CancelAll();
+ }
+
+ private:
+ void Cleanup() {
+ if (!root_)
+ return;
+ // The ActivationClient may have been destroyed by the time we get here.
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(root_);
+ if (client)
+ client->RemoveObserver(this);
+ root_->RemovePreTargetHandler(this);
+ root_->RemoveObserver(this);
+ root_ = NULL;
+ }
+
+ MenuController* controller_;
+ aura::Window* root_;
+
+ DISALLOW_COPY_AND_ASSIGN(ActivationChangeObserverImpl);
+};
+
+} // namespace
+
+// static
+MenuMessageLoop* MenuMessageLoop::Create() {
+ return new MenuMessageLoopAura;
+}
+
+MenuMessageLoopAura::MenuMessageLoopAura() : owner_(NULL) {
+}
+
+MenuMessageLoopAura::~MenuMessageLoopAura() {
+}
+
+void MenuMessageLoopAura::RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) {
+ aura::Window* root = window->GetRootWindow();
+ ScreenPositionClient* spc = aura::client::GetScreenPositionClient(root);
+ if (!spc)
+ return;
+
+ gfx::Point root_loc(screen_loc);
+ spc->ConvertPointFromScreen(root, &root_loc);
+
+ ui::MouseEvent clone(static_cast<const ui::MouseEvent&>(event));
+ clone.set_location(root_loc);
+ clone.set_root_location(root_loc);
+ root->GetHost()->dispatcher()->RepostEvent(clone);
+}
+
+void MenuMessageLoopAura::Run(MenuController* controller,
+ Widget* owner,
+ bool nested_menu) {
+ // |owner_| may be NULL.
+ owner_ = owner;
+ aura::Window* root = GetOwnerRootWindow(owner_);
+ // It is possible for the same MenuMessageLoopAura to start a nested
+ // message-loop while it is already running a nested loop. So make sure the
+ // quit-closure gets reset to the outer loop's quit-closure once the innermost
+ // loop terminates.
+ base::AutoReset<base::Closure> reset_quit_closure(&message_loop_quit_,
+ base::Closure());
+
+#if defined(OS_WIN)
+ internal::MenuMessagePumpDispatcher nested_dispatcher(controller);
+ if (root) {
+ scoped_ptr<ActivationChangeObserverImpl> observer;
+ if (!nested_menu)
+ observer.reset(new ActivationChangeObserverImpl(controller, root));
+ aura::client::DispatcherRunLoop run_loop(
+ aura::client::GetDispatcherClient(root), &nested_dispatcher);
+ message_loop_quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+ } else {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ base::RunLoop run_loop(&nested_dispatcher);
+ message_loop_quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+#else
+ internal::MenuEventDispatcher event_dispatcher(controller);
+ scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher =
+ nested_dispatcher_.Pass();
+ if (ui::PlatformEventSource::GetInstance()) {
+ nested_dispatcher_ =
+ ui::PlatformEventSource::GetInstance()->OverrideDispatcher(
+ &event_dispatcher);
+ }
+ if (root) {
+ scoped_ptr<ActivationChangeObserverImpl> observer;
+ if (!nested_menu)
+ observer.reset(new ActivationChangeObserverImpl(controller, root));
+ aura::client::DispatcherRunLoop run_loop(
+ aura::client::GetDispatcherClient(root), NULL);
+ message_loop_quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+ } else {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ base::RunLoop run_loop;
+ message_loop_quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+ nested_dispatcher_ = old_dispatcher.Pass();
+#endif
+}
+
+bool MenuMessageLoopAura::ShouldQuitNow() const {
+ aura::Window* root = GetOwnerRootWindow(owner_);
+ return !aura::client::GetDragDropClient(root) ||
+ !aura::client::GetDragDropClient(root)->IsDragDropInProgress();
+}
+
+void MenuMessageLoopAura::QuitNow() {
+ CHECK(!message_loop_quit_.is_null());
+ message_loop_quit_.Run();
+ // Restore the previous dispatcher.
+ nested_dispatcher_.reset();
+}
+
+void MenuMessageLoopAura::ClearOwner() {
+ owner_ = NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_aura.h b/chromium/ui/views/controls/menu/menu_message_loop_aura.h
new file mode 100644
index 00000000000..49e8a392827
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop_aura.h
@@ -0,0 +1,52 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_AURA_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_AURA_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/views/controls/menu/menu_message_loop.h"
+
+namespace base {
+class MessagePumpDispatcher;
+}
+
+namespace ui {
+class ScopedEventDispatcher;
+}
+
+namespace views {
+
+class MenuMessageLoopAura : public MenuMessageLoop {
+ public:
+ MenuMessageLoopAura();
+ virtual ~MenuMessageLoopAura();
+
+ // Overridden from MenuMessageLoop:
+ virtual void Run(MenuController* controller,
+ Widget* owner,
+ bool nested_menu) OVERRIDE;
+ virtual bool ShouldQuitNow() const OVERRIDE;
+ virtual void QuitNow() OVERRIDE;
+ virtual void RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) OVERRIDE;
+ virtual void ClearOwner() OVERRIDE;
+
+ private:
+ // Owner of child windows.
+ // WARNING: this may be NULL.
+ Widget* owner_;
+
+ scoped_ptr<ui::ScopedEventDispatcher> nested_dispatcher_;
+ base::Closure message_loop_quit_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuMessageLoopAura);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_AURA_H_
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_mac.cc b/chromium/ui/views/controls/menu/menu_message_loop_mac.cc
new file mode 100644
index 00000000000..b1c10cca7d8
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop_mac.cc
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_message_loop_mac.h"
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "ui/gfx/geometry/point.h"
+
+namespace views {
+
+// static
+MenuMessageLoop* MenuMessageLoop::Create() {
+ return new MenuMessageLoopMac;
+}
+
+MenuMessageLoopMac::MenuMessageLoopMac() {
+}
+
+MenuMessageLoopMac::~MenuMessageLoopMac() {
+}
+
+void MenuMessageLoopMac::RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) {
+ NOTIMPLEMENTED();
+}
+
+void MenuMessageLoopMac::Run(MenuController* controller,
+ Widget* owner,
+ bool nested_menu) {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ base::RunLoop run_loop;
+ run_loop.Run();
+}
+
+bool MenuMessageLoopMac::ShouldQuitNow() const {
+ return true;
+}
+
+void MenuMessageLoopMac::QuitNow() {
+ base::MessageLoop::current()->QuitNow();
+}
+
+void MenuMessageLoopMac::ClearOwner() {
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_mac.h b/chromium/ui/views/controls/menu/menu_message_loop_mac.h
new file mode 100644
index 00000000000..b77d263ffbb
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop_mac.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_MAC_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_MAC_H_
+
+#include "base/compiler_specific.h"
+#include "ui/views/controls/menu/menu_message_loop.h"
+
+namespace views {
+
+class MenuMessageLoopMac : public MenuMessageLoop {
+ public:
+ MenuMessageLoopMac();
+ virtual ~MenuMessageLoopMac();
+
+ // Overridden from MenuMessageLoop:
+ virtual void Run(MenuController* controller,
+ Widget* owner,
+ bool nested_menu) OVERRIDE;
+ virtual bool ShouldQuitNow() const OVERRIDE;
+ virtual void QuitNow() OVERRIDE;
+ virtual void RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) OVERRIDE;
+ virtual void ClearOwner() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MenuMessageLoopMac);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_MAC_H_
diff --git a/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc b/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc
new file mode 100644
index 00000000000..8f905d029ae
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_message_pump_dispatcher_win.h"
+
+#include <windowsx.h>
+
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+
+namespace views {
+namespace internal {
+
+MenuMessagePumpDispatcher::MenuMessagePumpDispatcher(MenuController* controller)
+ : menu_controller_(controller) {}
+
+MenuMessagePumpDispatcher::~MenuMessagePumpDispatcher() {}
+
+uint32_t MenuMessagePumpDispatcher::Dispatch(const MSG& msg) {
+ DCHECK(menu_controller_->IsBlockingRun());
+
+ bool should_quit = false;
+ bool should_perform_default = true;
+ if (menu_controller_->exit_type() == MenuController::EXIT_ALL ||
+ menu_controller_->exit_type() == MenuController::EXIT_DESTROYED) {
+ should_quit = true;
+ } else {
+ // NOTE: we don't get WM_ACTIVATE or anything else interesting in here.
+ switch (msg.message) {
+ case WM_CONTEXTMENU: {
+ MenuItemView* item = menu_controller_->pending_state_.item;
+ if (item && item->GetRootMenuItem() != item) {
+ gfx::Point screen_loc(0, item->height());
+ View::ConvertPointToScreen(item, &screen_loc);
+ ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE;
+ if (GET_X_LPARAM(msg.lParam) == -1 && GET_Y_LPARAM(msg.lParam) == -1)
+ source_type = ui::MENU_SOURCE_KEYBOARD;
+ item->GetDelegate()->ShowContextMenu(
+ item, item->GetCommand(), screen_loc, source_type);
+ }
+ should_quit = false;
+ should_perform_default = false;
+ break;
+ }
+
+ // NOTE: focus wasn't changed when the menu was shown. As such, don't
+ // dispatch key events otherwise the focused window will get the events.
+ case WM_KEYDOWN: {
+ bool result =
+ menu_controller_->OnKeyDown(ui::KeyboardCodeFromNative(msg));
+ TranslateMessage(&msg);
+ should_perform_default = false;
+ should_quit = !result;
+ break;
+ }
+ case WM_CHAR: {
+ should_quit = menu_controller_->SelectByChar(
+ static_cast<base::char16>(msg.wParam));
+ should_perform_default = false;
+ break;
+ }
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ // We may have been shown on a system key, as such don't do anything
+ // here. If another system key is pushed we'll get a WM_SYSKEYDOWN and
+ // close the menu.
+ should_quit = false;
+ should_perform_default = false;
+ break;
+
+ case WM_CANCELMODE:
+ case WM_SYSKEYDOWN:
+ // Exit immediately on system keys.
+ menu_controller_->Cancel(MenuController::EXIT_ALL);
+ should_quit = true;
+ should_perform_default = false;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (should_quit || menu_controller_->exit_type() != MenuController::EXIT_NONE)
+ menu_controller_->TerminateNestedMessageLoop();
+ return should_perform_default ? POST_DISPATCH_PERFORM_DEFAULT
+ : POST_DISPATCH_NONE;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.h b/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.h
new file mode 100644
index 00000000000..31f1b369610
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.h
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_PUMP_DISPATCHER_WIN_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_PUMP_DISPATCHER_WIN_H_
+
+#include "base/macros.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+
+namespace views {
+
+class MenuController;
+
+namespace internal {
+
+// A message-pump dispatcher object used to dispatch events from the nested
+// message-loop initiated by the MenuController.
+class MenuMessagePumpDispatcher : public base::MessagePumpDispatcher {
+ public:
+ explicit MenuMessagePumpDispatcher(MenuController* menu_controller);
+ virtual ~MenuMessagePumpDispatcher();
+
+ private:
+ // base::MessagePumpDispatcher:
+ virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE;
+
+ MenuController* menu_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuMessagePumpDispatcher);
+};
+
+} // namespace internal
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_PUMP_DISPATCHER_WIN_H_
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index 07f1f403fd8..55c5d7d21d9 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -8,6 +8,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/image/image.h"
+#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/views_delegate.h"
@@ -59,7 +60,7 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model,
int item_id) {
gfx::Image icon;
model->GetIconAt(model_index, &icon);
- string16 label, sublabel, minor_text;
+ base::string16 label, sublabel, minor_text;
ui::MenuSeparatorType separator_style = ui::NORMAL_SEPARATOR;
MenuItemView::Type type;
ui::MenuModel::ItemType menu_type = model->GetTypeAt(model_index);
@@ -161,7 +162,7 @@ bool MenuModelAdapter::IsTriggerableEvent(MenuItemView* source,
}
bool MenuModelAdapter::GetAccelerator(int id,
- ui::Accelerator* accelerator) {
+ ui::Accelerator* accelerator) const {
ui::MenuModel* model = menu_model_;
int index = 0;
if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
@@ -171,27 +172,27 @@ bool MenuModelAdapter::GetAccelerator(int id,
return false;
}
-string16 MenuModelAdapter::GetLabel(int id) const {
+base::string16 MenuModelAdapter::GetLabel(int id) const {
ui::MenuModel* model = menu_model_;
int index = 0;
if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
return model->GetLabelAt(index);
NOTREACHED();
- return string16();
+ return base::string16();
}
-const gfx::Font* MenuModelAdapter::GetLabelFont(int id) const {
+const gfx::FontList* MenuModelAdapter::GetLabelFontList(int id) const {
ui::MenuModel* model = menu_model_;
int index = 0;
if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
- const gfx::Font* font = model->GetLabelFontAt(index);
- if (font)
- return font;
+ const gfx::FontList* font_list = model->GetLabelFontListAt(index);
+ if (font_list)
+ return font_list;
}
// This line may be reached for the empty menu item.
- return MenuDelegate::GetLabelFont(id);
+ return MenuDelegate::GetLabelFontList(id);
}
bool MenuModelAdapter::IsCommandEnabled(int id) const {
@@ -204,6 +205,16 @@ bool MenuModelAdapter::IsCommandEnabled(int id) const {
return false;
}
+bool MenuModelAdapter::IsCommandVisible(int id) const {
+ ui::MenuModel* model = menu_model_;
+ int index = 0;
+ if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
+ return model->IsVisibleAt(index);
+
+ NOTREACHED();
+ return false;
+}
+
bool MenuModelAdapter::IsItemChecked(int id) const {
ui::MenuModel* model = menu_model_;
int index = 0;
@@ -264,9 +275,6 @@ void MenuModelAdapter::BuildMenuImpl(MenuItemView* menu, ui::MenuModel* model) {
for (int i = 0; i < item_count; ++i) {
MenuItemView* item = AppendMenuItem(menu, model, i);
- if (item)
- item->SetVisible(model->IsVisibleAt(i));
-
if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) {
DCHECK(item);
DCHECK_EQ(MenuItemView::SUBMENU, item->GetType());
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.h b/chromium/ui/views/controls/menu/menu_model_adapter.h
index 4db9dbe2cf9..353d010c533 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.h
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.h
@@ -67,10 +67,11 @@ class VIEWS_EXPORT MenuModelAdapter : public MenuDelegate {
virtual bool IsTriggerableEvent(MenuItemView* source,
const ui::Event& e) OVERRIDE;
virtual bool GetAccelerator(int id,
- ui::Accelerator* accelerator) OVERRIDE;
- virtual string16 GetLabel(int id) const OVERRIDE;
- virtual const gfx::Font* GetLabelFont(int id) const OVERRIDE;
+ ui::Accelerator* accelerator) const OVERRIDE;
+ virtual base::string16 GetLabel(int id) const OVERRIDE;
+ virtual const gfx::FontList* GetLabelFontList(int id) const OVERRIDE;
virtual bool IsCommandEnabled(int id) const OVERRIDE;
+ virtual bool IsCommandVisible(int id) const OVERRIDE;
virtual bool IsItemChecked(int id) const OVERRIDE;
virtual void SelectionChanged(MenuItemView* menu) OVERRIDE;
virtual void WillShowMenu(MenuItemView* menu) OVERRIDE;
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
index 6ce3a376270..cba4d2fa7fb 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/controls/menu/menu_model_adapter.h"
+
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/models/menu_model_delegate.h"
#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/test/views_test_base.h"
@@ -51,7 +52,7 @@ class MenuModelBase : public ui::MenuModel {
return index + command_id_base_;
}
- virtual string16 GetLabelAt(int index) const OVERRIDE {
+ virtual base::string16 GetLabelAt(int index) const OVERRIDE {
return items_[index].label;
}
@@ -59,7 +60,7 @@ class MenuModelBase : public ui::MenuModel {
return false;
}
- virtual const gfx::Font* GetLabelFontAt(int index) const OVERRIDE {
+ virtual const gfx::FontList* GetLabelFontListAt(int index) const OVERRIDE {
return NULL;
}
@@ -128,12 +129,12 @@ class MenuModelBase : public ui::MenuModel {
const std::string& item_label,
ui::MenuModel* item_submenu)
: type(item_type),
- label(ASCIIToUTF16(item_label)),
+ label(base::ASCIIToUTF16(item_label)),
submenu(item_submenu) {
}
ItemType type;
- string16 label;
+ base::string16 label;
ui::MenuModel* submenu;
};
diff --git a/chromium/ui/views/controls/menu/menu_runner.cc b/chromium/ui/views/controls/menu/menu_runner.cc
index e254dbffc55..ca36d026433 100644
--- a/chromium/ui/views/controls/menu/menu_runner.cc
+++ b/chromium/ui/views/controls/menu/menu_runner.cc
@@ -12,6 +12,7 @@
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/controls/menu/menu_controller_delegate.h"
#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner_handler.h"
#include "ui/views/widget/widget.h"
@@ -43,7 +44,7 @@ class MenuRunnerImpl : public internal::MenuControllerDelegate {
MenuRunner::RunResult RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
int32 types) WARN_UNUSED_RESULT;
void Cancel();
@@ -140,12 +141,11 @@ void MenuRunnerImpl::Release() {
}
}
-MenuRunner::RunResult MenuRunnerImpl::RunMenuAt(
- Widget* parent,
- MenuButton* button,
- const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
- int32 types) {
+MenuRunner::RunResult MenuRunnerImpl::RunMenuAt(Widget* parent,
+ MenuButton* button,
+ const gfx::Rect& bounds,
+ MenuAnchorPosition anchor,
+ int32 types) {
closing_event_time_ = base::TimeDelta();
if (running_) {
// Ignore requests to show the menu while it's already showing. MenuItemView
@@ -186,7 +186,7 @@ MenuRunner::RunResult MenuRunnerImpl::RunMenuAt(
controller = new MenuController(theme, !for_drop_, this);
owns_controller_ = true;
}
- controller->set_accept_on_f4((types & MenuRunner::COMBOBOX) != 0);
+ controller->set_is_combobox((types & MenuRunner::COMBOBOX) != 0);
controller_ = controller;
menu_->set_controller(controller_);
menu_->PrepareForRun(owns_controller_,
@@ -278,16 +278,6 @@ bool MenuRunnerImpl::ShouldShowMnemonics(MenuButton* button) {
return show_mnemonics;
}
-// In theory we could implement this every where, but for now we're only
-// implementing it on aura.
-#if !defined(USE_AURA)
-// static
-DisplayChangeListener* DisplayChangeListener::Create(Widget* widget,
- MenuRunner* runner) {
- return NULL;
-}
-#endif
-
} // namespace internal
MenuRunner::MenuRunner(ui::MenuModel* menu_model)
@@ -310,7 +300,7 @@ MenuItemView* MenuRunner::GetMenu() {
MenuRunner::RunResult MenuRunner::RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
ui::MenuSourceType source_type,
int32 types) {
if (runner_handler_.get()) {
@@ -331,11 +321,11 @@ MenuRunner::RunResult MenuRunner::RunMenuAt(Widget* parent,
case ui::MENU_SOURCE_NONE:
case ui::MENU_SOURCE_KEYBOARD:
case ui::MENU_SOURCE_MOUSE:
- anchor = MenuItemView::TOPLEFT;
+ anchor = MENU_ANCHOR_TOPLEFT;
break;
case ui::MENU_SOURCE_TOUCH:
case ui::MENU_SOURCE_TOUCH_EDIT_MENU:
- anchor = MenuItemView::BOTTOMCENTER;
+ anchor = MENU_ANCHOR_BOTTOMCENTER;
break;
default:
break;
diff --git a/chromium/ui/views/controls/menu/menu_runner.h b/chromium/ui/views/controls/menu/menu_runner.h
index 6b46362f18e..824afdf8d4b 100644
--- a/chromium/ui/views/controls/menu/menu_runner.h
+++ b/chromium/ui/views/controls/menu/menu_runner.h
@@ -8,7 +8,17 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/menu/menu_types.h"
+#include "ui/views/views_export.h"
+
+namespace base {
+class TimeDelta;
+}
+
+namespace gfx {
+class Rect;
+}
namespace ui {
class MenuModel;
@@ -17,6 +27,7 @@ class MenuModel;
namespace views {
class MenuButton;
+class MenuItemView;
class MenuModelAdapter;
class MenuRunnerHandler;
class Widget;
@@ -103,7 +114,7 @@ class VIEWS_EXPORT MenuRunner {
RunResult RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
ui::MenuSourceType source_type,
int32 types) WARN_UNUSED_RESULT;
diff --git a/chromium/ui/views/controls/menu/menu_runner_handler.h b/chromium/ui/views/controls/menu/menu_runner_handler.h
index 46f801af685..47d75c80fce 100644
--- a/chromium/ui/views/controls/menu/menu_runner_handler.h
+++ b/chromium/ui/views/controls/menu/menu_runner_handler.h
@@ -6,11 +6,11 @@
#define UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_HANDLER_H_
#include "base/basictypes.h"
-#include "ui/views/controls/menu/menu_item_view.h"
namespace views {
class MenuButton;
+class MenuItemView;
class Widget;
// Used internally by MenuRunner to show the menu. Can be set in tests (see
@@ -21,7 +21,7 @@ class VIEWS_EXPORT MenuRunnerHandler {
virtual MenuRunner::RunResult RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
ui::MenuSourceType source_type,
int32 types) = 0;
};
diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
index 7b8edbecab5..451bd1537ad 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -6,8 +6,9 @@
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
+#include "ui/native_theme/native_theme_aura.h"
#include "ui/views/border.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/menu/menu_config.h"
@@ -16,10 +17,6 @@
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/round_rect_painter.h"
-#if defined(USE_AURA)
-#include "ui/native_theme/native_theme_aura.h"
-#endif
-
using ui::NativeTheme;
namespace views {
@@ -43,7 +40,7 @@ class MenuScrollButton : public View {
pref_height_(MenuItemView::pref_menu_height()) {
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return gfx::Size(
host_->GetMenuItem()->GetMenuConfig().scroll_arrow_height * 2 - 1,
pref_height_);
@@ -246,7 +243,7 @@ void MenuScrollViewContainer::Layout() {
scroll_view_->Layout();
}
-gfx::Size MenuScrollViewContainer::GetPreferredSize() {
+gfx::Size MenuScrollViewContainer::GetPreferredSize() const {
gfx::Size prefsize = scroll_view_->GetContents()->GetPreferredSize();
gfx::Insets insets = GetInsets();
prefsize.Enlarge(insets.width(), insets.height());
@@ -254,15 +251,15 @@ gfx::Size MenuScrollViewContainer::GetPreferredSize() {
}
void MenuScrollViewContainer::GetAccessibleState(
- ui::AccessibleViewState* state) {
+ ui::AXViewState* state) {
// Get the name from the submenu view.
content_view_->GetAccessibleState(state);
// Now change the role.
- state->role = ui::AccessibilityTypes::ROLE_MENUBAR;
+ state->role = ui::AX_ROLE_MENU_BAR;
// Some AT (like NVDA) will not process focus events on menu item children
// unless a parent claims to be focused.
- state->state = ui::AccessibilityTypes::STATE_FOCUSED;
+ state->AddStateFlag(ui::AX_STATE_FOCUSED);
}
void MenuScrollViewContainer::OnBoundsChanged(
@@ -284,7 +281,7 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
int padding = menu_config.corner_radius > 0 ?
kBorderPaddingDueToRoundedCorners : 0;
-#if defined(USE_AURA)
+#if defined(USE_AURA) && !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
if (menu_config.native_theme == ui::NativeThemeAura::instance()) {
// In case of NativeThemeAura the border gets drawn with the shadow.
// Furthermore no additional padding is wanted.
@@ -299,13 +296,14 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
int right = menu_config.menu_horizontal_border_size + padding;
if (use_border) {
- set_border(views::Border::CreateBorderPainter(
- new views::RoundRectPainter(menu_config.native_theme->GetSystemColor(
+ SetBorder(views::Border::CreateBorderPainter(
+ new views::RoundRectPainter(
+ menu_config.native_theme->GetSystemColor(
ui::NativeTheme::kColorId_MenuBorderColor),
menu_config.corner_radius),
- gfx::Insets(top, left, bottom, right)));
+ gfx::Insets(top, left, bottom, right)));
} else {
- set_border(Border::CreateEmptyBorder(top, left, bottom, right));
+ SetBorder(Border::CreateEmptyBorder(top, left, bottom, right));
}
}
@@ -313,21 +311,20 @@ void MenuScrollViewContainer::CreateBubbleBorder() {
bubble_border_ = new BubbleBorder(arrow_,
BubbleBorder::SMALL_SHADOW,
SK_ColorWHITE);
- set_border(bubble_border_);
+ SetBorder(scoped_ptr<Border>(bubble_border_));
set_background(new BubbleBackground(bubble_border_));
}
-BubbleBorder::Arrow
-MenuScrollViewContainer::BubbleBorderTypeFromAnchor(
- MenuItemView::AnchorPosition anchor) {
+BubbleBorder::Arrow MenuScrollViewContainer::BubbleBorderTypeFromAnchor(
+ MenuAnchorPosition anchor) {
switch (anchor) {
- case views::MenuItemView::BUBBLE_LEFT:
+ case MENU_ANCHOR_BUBBLE_LEFT:
return BubbleBorder::RIGHT_CENTER;
- case views::MenuItemView::BUBBLE_RIGHT:
+ case MENU_ANCHOR_BUBBLE_RIGHT:
return BubbleBorder::LEFT_CENTER;
- case views::MenuItemView::BUBBLE_ABOVE:
+ case MENU_ANCHOR_BUBBLE_ABOVE:
return BubbleBorder::BOTTOM_CENTER;
- case views::MenuItemView::BUBBLE_BELOW:
+ case MENU_ANCHOR_BUBBLE_BELOW:
return BubbleBorder::TOP_CENTER;
default:
return BubbleBorder::NONE;
diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.h b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
index 83baa2a3939..dc7c1acf164 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
@@ -7,7 +7,7 @@
#include "ui/views/view.h"
#include "ui/views/bubble/bubble_border.h"
-#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/controls/menu/menu_types.h"
namespace views {
@@ -33,8 +33,8 @@ class MenuScrollViewContainer : public View {
// View overrides.
virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// View override.
@@ -47,8 +47,7 @@ class MenuScrollViewContainer : public View {
// Create the bubble border.
void CreateBubbleBorder();
- BubbleBorder::Arrow BubbleBorderTypeFromAnchor(
- MenuItemView::AnchorPosition anchor);
+ BubbleBorder::Arrow BubbleBorderTypeFromAnchor(MenuAnchorPosition anchor);
class MenuScrollView;
@@ -65,7 +64,7 @@ class MenuScrollViewContainer : public View {
// If set the currently set border is a bubble border.
BubbleBorder::Arrow arrow_;
- // The currently set border.
+ // Weak reference to the currently set border.
BubbleBorder* bubble_border_;
DISALLOW_COPY_AND_ASSIGN(MenuScrollViewContainer);
diff --git a/chromium/ui/views/controls/menu/menu_separator.h b/chromium/ui/views/controls/menu/menu_separator.h
index 4098ae8f0ae..da459e2b07a 100644
--- a/chromium/ui/views/controls/menu/menu_separator.h
+++ b/chromium/ui/views/controls/menu/menu_separator.h
@@ -21,13 +21,11 @@ class MenuSeparator : public View {
// View overrides.
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
private:
-#if defined(USE_AURA)
void OnPaintAura(gfx::Canvas* canvas);
- gfx::Size GetPreferredSizeAura();
-#endif
+ gfx::Size GetPreferredSizeAura() const;
// The type of the separator.
const ui::MenuSeparatorType type_;
diff --git a/chromium/ui/views/controls/menu/menu_separator_views.cc b/chromium/ui/views/controls/menu/menu_separator_views.cc
index affbae48966..34f85453501 100644
--- a/chromium/ui/views/controls/menu/menu_separator_views.cc
+++ b/chromium/ui/views/controls/menu/menu_separator_views.cc
@@ -23,7 +23,7 @@ void MenuSeparator::OnPaint(gfx::Canvas* canvas) {
OnPaintAura(canvas);
}
-gfx::Size MenuSeparator::GetPreferredSize() {
+gfx::Size MenuSeparator::GetPreferredSize() const {
return GetPreferredSizeAura();
}
#endif
@@ -47,7 +47,7 @@ void MenuSeparator::OnPaintAura(gfx::Canvas* canvas) {
ui::NativeTheme::kColorId_MenuSeparatorColor));
}
-gfx::Size MenuSeparator::GetPreferredSizeAura() {
+gfx::Size MenuSeparator::GetPreferredSizeAura() const {
const MenuConfig& menu_config = parent_menu_item_->GetMenuConfig();
int height = menu_config.separator_height;
switch(type_) {
diff --git a/chromium/ui/views/controls/menu/menu_separator_win.cc b/chromium/ui/views/controls/menu/menu_separator_win.cc
index 6f95334790a..ccbcaed263e 100644
--- a/chromium/ui/views/controls/menu/menu_separator_win.cc
+++ b/chromium/ui/views/controls/menu/menu_separator_win.cc
@@ -11,24 +11,19 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/rect.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/native_theme/native_theme_aura.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_item_view.h"
-#if defined(USE_AURA)
-#include "ui/native_theme/native_theme_aura.h"
-#endif
-
namespace views {
void MenuSeparator::OnPaint(gfx::Canvas* canvas) {
const MenuConfig& config = parent_menu_item_->GetMenuConfig();
-#if defined(USE_AURA)
if (config.native_theme == ui::NativeThemeAura::instance()) {
OnPaintAura(canvas);
return;
}
-#endif
int start_x = 0;
if (config.render_gutter) {
@@ -52,13 +47,11 @@ void MenuSeparator::OnPaint(gfx::Canvas* canvas) {
ui::NativeTheme::kNormal, separator_bounds, extra);
}
-gfx::Size MenuSeparator::GetPreferredSize() {
+gfx::Size MenuSeparator::GetPreferredSize() const {
const MenuConfig& config = parent_menu_item_->GetMenuConfig();
-#if defined(USE_AURA)
if (config.native_theme == ui::NativeThemeAura::instance())
return GetPreferredSizeAura();
-#endif
return gfx::Size(10, // Just in case we're the only item in a menu.
config.separator_height);
diff --git a/chromium/ui/views/controls/menu/menu_types.h b/chromium/ui/views/controls/menu/menu_types.h
new file mode 100644
index 00000000000..160dd5ae3d1
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_types.h
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_TYPES_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_TYPES_H_
+
+namespace views {
+
+// Where a popup menu should be anchored to for non-RTL languages. The opposite
+// position will be used if base::i18n:IsRTL() is true. The BUBBLE flags are
+// used when the menu should get enclosed by a bubble. Note that BUBBLE flags
+// should only be used with menus which have no children.
+enum MenuAnchorPosition {
+ MENU_ANCHOR_TOPLEFT,
+ MENU_ANCHOR_TOPRIGHT,
+ MENU_ANCHOR_BOTTOMCENTER,
+ MENU_ANCHOR_BUBBLE_LEFT,
+ MENU_ANCHOR_BUBBLE_RIGHT,
+ MENU_ANCHOR_BUBBLE_ABOVE,
+ MENU_ANCHOR_BUBBLE_BELOW
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_TYPES_H_
diff --git a/chromium/ui/views/controls/menu/menu_win.cc b/chromium/ui/views/controls/menu/menu_win.cc
deleted file mode 100644
index d88659ff7d4..00000000000
--- a/chromium/ui/views/controls/menu/menu_win.cc
+++ /dev/null
@@ -1,572 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/menu/menu_win.h"
-
-#include <string>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/win/window_impl.h"
-#include "ui/views/layout/layout_constants.h"
-
-namespace views {
-
-// The width of an icon, including the pixels between the icon and
-// the item label.
-const int kIconWidth = 23;
-// Margins between the top of the item and the label.
-const int kItemTopMargin = 3;
-// Margins between the bottom of the item and the label.
-const int kItemBottomMargin = 4;
-// Margins between the left of the item and the icon.
-const int kItemLeftMargin = 4;
-// The width for displaying the sub-menu arrow.
-const int kArrowWidth = 10;
-
-// Current active MenuHostWindow. If NULL, no menu is active.
-static MenuHostWindow* active_host_window = NULL;
-
-// The data of menu items needed to display.
-struct MenuWin::ItemData {
- string16 label;
- gfx::ImageSkia icon;
- bool submenu;
-};
-
-namespace {
-
-static int ChromeGetMenuItemID(HMENU hMenu, int pos) {
- // The built-in Windows GetMenuItemID doesn't work for submenus,
- // so here's our own implementation.
- MENUITEMINFO mii = {0};
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_ID;
- GetMenuItemInfo(hMenu, pos, TRUE, &mii);
- return mii.wID;
-}
-
-// MenuHostWindow -------------------------------------------------------------
-
-// MenuHostWindow is the HWND the HMENU is parented to. MenuHostWindow is used
-// to intercept right clicks on the HMENU and notify the delegate as well as
-// for drawing icons.
-//
-class MenuHostWindow : public gfx::WindowImpl {
- public:
- MenuHostWindow(MenuWin* menu, HWND parent_window) : menu_(menu) {
- int extended_style = 0;
- // If the menu needs to be created with a right-to-left UI layout, we must
- // set the appropriate RTL flags (such as WS_EX_LAYOUTRTL) property for the
- // underlying HWND.
- if (menu_->delegate()->IsRightToLeftUILayout())
- extended_style |= l10n_util::GetExtendedStyles();
- set_window_style(WS_CHILD);
- set_window_ex_style(extended_style);
- Init(parent_window, gfx::Rect());
- }
-
- ~MenuHostWindow() {
- DestroyWindow(hwnd());
- }
-
- BEGIN_MSG_MAP_EX(MenuHostWindow);
- MSG_WM_RBUTTONUP(OnRButtonUp)
- MSG_WM_MEASUREITEM(OnMeasureItem)
- MSG_WM_DRAWITEM(OnDrawItem)
- END_MSG_MAP();
-
- private:
- // NOTE: I really REALLY tried to use WM_MENURBUTTONUP, but I ran into
- // two problems in using it:
- // 1. It doesn't contain the coordinates of the mouse.
- // 2. It isn't invoked for menuitems representing a submenu that have children
- // menu items (not empty).
-
- void OnRButtonUp(UINT w_param, const CPoint& loc) {
- int id;
- if (menu_->delegate() && FindMenuIDByLocation(menu_, loc, &id))
- menu_->delegate()->ShowContextMenu(menu_, id, gfx::Point(loc), true);
- }
-
- void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* lpmis) {
- MenuWin::ItemData* data =
- reinterpret_cast<MenuWin::ItemData*>(lpmis->itemData);
- if (data != NULL) {
- gfx::Font font;
- lpmis->itemWidth = font.GetStringWidth(data->label) + kIconWidth +
- kItemLeftMargin + views::kItemLabelSpacing -
- GetSystemMetrics(SM_CXMENUCHECK);
- if (data->submenu)
- lpmis->itemWidth += kArrowWidth;
- // If the label contains an accelerator, make room for tab.
- if (data->label.find(L'\t') != string16::npos)
- lpmis->itemWidth += font.GetStringWidth(L" ");
- lpmis->itemHeight = font.GetHeight() + kItemBottomMargin + kItemTopMargin;
- } else {
- // Measure separator size.
- lpmis->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
- lpmis->itemWidth = 0;
- }
- }
-
- void OnDrawItem(UINT wParam, DRAWITEMSTRUCT* lpdis) {
- HDC hDC = lpdis->hDC;
- COLORREF prev_bg_color, prev_text_color;
-
- // Set background color and text color
- if (lpdis->itemState & ODS_SELECTED) {
- prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
- prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
- } else {
- prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_MENU));
- if (lpdis->itemState & ODS_DISABLED)
- prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
- else
- prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_MENUTEXT));
- }
-
- if (lpdis->itemData) {
- MenuWin::ItemData* data =
- reinterpret_cast<MenuWin::ItemData*>(lpdis->itemData);
-
- // Draw the background.
- HBRUSH hbr = CreateSolidBrush(GetBkColor(hDC));
- FillRect(hDC, &lpdis->rcItem, hbr);
- DeleteObject(hbr);
-
- // Draw the label.
- RECT rect = lpdis->rcItem;
- rect.top += kItemTopMargin;
- // Should we add kIconWidth only when icon.width() != 0 ?
- rect.left += kItemLeftMargin + kIconWidth;
- rect.right -= views::kItemLabelSpacing;
- UINT format = DT_TOP | DT_SINGLELINE;
- // Check whether the mnemonics should be underlined.
- BOOL underline_mnemonics;
- SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
- if (!underline_mnemonics)
- format |= DT_HIDEPREFIX;
- gfx::Font font;
- HGDIOBJ old_font =
- static_cast<HFONT>(SelectObject(hDC, font.GetNativeFont()));
-
- // If an accelerator is specified (with a tab delimiting the rest of the
- // label from the accelerator), we have to justify the fist part on the
- // left and the accelerator on the right.
- // TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
- // window system UI font and will not hit here.
- string16 label = data->label;
- string16 accel;
- string16::size_type tab_pos = label.find(L'\t');
- if (tab_pos != string16::npos) {
- accel = label.substr(tab_pos);
- label = label.substr(0, tab_pos);
- }
- DrawTextEx(hDC, const_cast<wchar_t*>(label.data()),
- static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
- if (!accel.empty())
- DrawTextEx(hDC, const_cast<wchar_t*>(accel.data()),
- static_cast<int>(accel.size()), &rect,
- format | DT_RIGHT, NULL);
- SelectObject(hDC, old_font);
-
- // Draw the icon after the label, otherwise it would be covered
- // by the label.
- gfx::ImageSkiaRep icon_image_rep = data->icon.GetRepresentation(1.0f);
- if (data->icon.width() != 0 && data->icon.height() != 0) {
- gfx::Canvas canvas(icon_image_rep, false);
- skia::DrawToNativeContext(
- canvas.sk_canvas(), hDC, lpdis->rcItem.left + kItemLeftMargin,
- lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top -
- data->icon.height()) / 2, NULL);
- }
-
- } else {
- // Draw the separator
- lpdis->rcItem.top += (lpdis->rcItem.bottom - lpdis->rcItem.top) / 3;
- DrawEdge(hDC, &lpdis->rcItem, EDGE_ETCHED, BF_TOP);
- }
-
- SetBkColor(hDC, prev_bg_color);
- SetTextColor(hDC, prev_text_color);
- }
-
- bool FindMenuIDByLocation(MenuWin* menu, const CPoint& loc, int* id) {
- int index = MenuItemFromPoint(NULL, menu->menu_, loc);
- if (index != -1) {
- *id = ChromeGetMenuItemID(menu->menu_, index);
- return true;
- } else {
- for (std::vector<MenuWin*>::iterator i = menu->submenus_.begin();
- i != menu->submenus_.end(); ++i) {
- if (FindMenuIDByLocation(*i, loc, id))
- return true;
- }
- }
- return false;
- }
-
- // The menu that created us.
- MenuWin* menu_;
-
- DISALLOW_COPY_AND_ASSIGN(MenuHostWindow);
-};
-
-} // namespace
-
-// static
-Menu* Menu::Create(Delegate* delegate,
- AnchorPoint anchor,
- gfx::NativeView parent) {
- return new MenuWin(delegate, anchor, parent);
-}
-
-// static
-Menu* Menu::GetSystemMenu(gfx::NativeWindow parent) {
- return new views::MenuWin(::GetSystemMenu(parent, FALSE));
-}
-
-MenuWin::MenuWin(Delegate* d, AnchorPoint anchor, HWND owner)
- : Menu(d, anchor),
- menu_(CreatePopupMenu()),
- owner_(owner),
- is_menu_visible_(false),
- owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL)) {
- DCHECK(delegate());
-}
-
-MenuWin::MenuWin(HMENU hmenu)
- : Menu(NULL, TOPLEFT),
- menu_(hmenu),
- owner_(NULL),
- is_menu_visible_(false),
- owner_draw_(false) {
- DCHECK(menu_);
-}
-
-MenuWin::~MenuWin() {
- STLDeleteContainerPointers(submenus_.begin(), submenus_.end());
- STLDeleteContainerPointers(item_data_.begin(), item_data_.end());
- DestroyMenu(menu_);
-}
-
-void MenuWin::AddMenuItemWithIcon(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon) {
- owner_draw_ = true;
- Menu::AddMenuItemWithIcon(index, item_id, label, icon);
-}
-
-Menu* MenuWin::AddSubMenuWithIcon(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon) {
- MenuWin* submenu = new MenuWin(this);
- submenus_.push_back(submenu);
- AddMenuItemInternal(index, item_id, label, icon, submenu->menu_, NORMAL);
- return submenu;
-}
-
-void MenuWin::AddSeparator(int index) {
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_FTYPE;
- mii.fType = MFT_SEPARATOR;
- InsertMenuItem(menu_, index, TRUE, &mii);
-}
-
-void MenuWin::EnableMenuItemByID(int item_id, bool enabled) {
- UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED;
- EnableMenuItem(menu_, item_id, MF_BYCOMMAND | enable_flags);
-}
-
-void MenuWin::EnableMenuItemAt(int index, bool enabled) {
- UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED;
- EnableMenuItem(menu_, index, MF_BYPOSITION | enable_flags);
-}
-
-void MenuWin::SetMenuLabel(int item_id, const string16& label) {
- MENUITEMINFO mii = {0};
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STRING;
- mii.dwTypeData = const_cast<wchar_t*>(label.c_str());
- mii.cch = static_cast<UINT>(label.size());
- SetMenuItemInfo(menu_, item_id, false, &mii);
-}
-
-bool MenuWin::SetIcon(const gfx::ImageSkia& icon, int item_id) {
- if (!owner_draw_)
- owner_draw_ = true;
-
- const int num_items = GetMenuItemCount(menu_);
- int sep_count = 0;
- for (int i = 0; i < num_items; ++i) {
- if (!(GetMenuState(menu_, i, MF_BYPOSITION) & MF_SEPARATOR)) {
- if (ChromeGetMenuItemID(menu_, i) == item_id) {
- item_data_[i - sep_count]->icon = icon;
- // When the menu is running, we use SetMenuItemInfo to let Windows
- // update the item information so that the icon being displayed
- // could change immediately.
- if (active_host_window) {
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_FTYPE | MIIM_DATA;
- mii.fType = MFT_OWNERDRAW;
- mii.dwItemData =
- reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]);
- SetMenuItemInfo(menu_, item_id, false, &mii);
- }
- return true;
- }
- } else {
- ++sep_count;
- }
- }
-
- // Continue searching for the item in submenus.
- for (size_t i = 0; i < submenus_.size(); ++i) {
- if (submenus_[i]->SetIcon(icon, item_id))
- return true;
- }
-
- return false;
-}
-
-void MenuWin::RunMenuAt(int x, int y) {
- SetMenuInfo();
-
- delegate()->MenuWillShow();
-
- // NOTE: we don't use TPM_RIGHTBUTTON here as it breaks selecting by way of
- // press, drag, release. See bugs 718 and 8560.
- UINT flags =
- GetTPMAlignFlags() | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE;
- is_menu_visible_ = true;
- DCHECK(owner_);
- // In order for context menus on menus to work, the context menu needs to
- // share the same window as the first menu is parented to.
- bool created_host = false;
- if (!active_host_window) {
- created_host = true;
- active_host_window = new MenuHostWindow(this, owner_);
- }
- UINT selected_id =
- TrackPopupMenuEx(menu_, flags, x, y, active_host_window->hwnd(), NULL);
- if (created_host) {
- delete active_host_window;
- active_host_window = NULL;
- }
- is_menu_visible_ = false;
-
- // Execute the chosen command
- if (selected_id != 0)
- delegate()->ExecuteCommand(selected_id);
-}
-
-void MenuWin::Cancel() {
- DCHECK(is_menu_visible_);
- EndMenu();
-}
-
-int MenuWin::ItemCount() {
- return GetMenuItemCount(menu_);
-}
-
-void MenuWin::AddMenuItemInternal(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon,
- MenuItemType type) {
- AddMenuItemInternal(index, item_id, label, icon, NULL, type);
-}
-
-void MenuWin::AddMenuItemInternal(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon,
- HMENU submenu,
- MenuItemType type) {
- DCHECK(type != SEPARATOR) << "Call AddSeparator instead!";
-
- if (!owner_draw_ && !icon.isNull())
- owner_draw_ = true;
-
- if (label.empty() && !delegate()) {
- // No label and no delegate; don't add an empty menu.
- // It appears under some circumstance we're getting an empty label
- // (l10n_util::GetStringUTF16(IDS_TASK_MANAGER) returns ""). This shouldn't
- // happen, but I'm working over the crash here.
- NOTREACHED();
- return;
- }
-
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_FTYPE | MIIM_ID;
- if (submenu) {
- mii.fMask |= MIIM_SUBMENU;
- mii.hSubMenu = submenu;
- }
-
- // Set the type and ID.
- if (!owner_draw_) {
- mii.fType = MFT_STRING;
- mii.fMask |= MIIM_STRING;
- } else {
- mii.fType = MFT_OWNERDRAW;
- }
-
- if (type == RADIO)
- mii.fType |= MFT_RADIOCHECK;
-
- mii.wID = item_id;
-
- // Set the item data.
- MenuWin::ItemData* data = new ItemData;
- item_data_.push_back(data);
- data->submenu = submenu != NULL;
-
- string16 actual_label(label.empty() ? delegate()->GetLabel(item_id) : label);
-
- // Find out if there is a shortcut we need to append to the label.
- ui::Accelerator accelerator(ui::VKEY_UNKNOWN, ui::EF_NONE);
- if (delegate() && delegate()->GetAcceleratorInfo(item_id, &accelerator)) {
- actual_label += L'\t';
- actual_label += accelerator.GetShortcutText();
- }
- labels_.push_back(actual_label);
-
- if (owner_draw_) {
- if (icon.width() != 0 && icon.height() != 0)
- data->icon = icon;
- else
- data->icon = delegate()->GetIcon(item_id);
- } else {
- mii.dwTypeData = const_cast<wchar_t*>(labels_.back().c_str());
- }
-
- InsertMenuItem(menu_, index, TRUE, &mii);
-}
-
-MenuWin::MenuWin(MenuWin* parent)
- : Menu(parent->delegate(), parent->anchor()),
- menu_(CreatePopupMenu()),
- owner_(parent->owner_),
- is_menu_visible_(false),
- owner_draw_(parent->owner_draw_) {
-}
-
-void MenuWin::SetMenuInfo() {
- const int num_items = GetMenuItemCount(menu_);
- int sep_count = 0;
- for (int i = 0; i < num_items; ++i) {
- MENUITEMINFO mii_info;
- mii_info.cbSize = sizeof(mii_info);
- // Get the menu's original type.
- mii_info.fMask = MIIM_FTYPE;
- GetMenuItemInfo(menu_, i, MF_BYPOSITION, &mii_info);
- // Set item states.
- if (!(mii_info.fType & MF_SEPARATOR)) {
- const int id = ChromeGetMenuItemID(menu_, i);
-
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STATE | MIIM_FTYPE | MIIM_DATA | MIIM_STRING;
- // We also need MFT_STRING for owner drawn items in order to let Windows
- // handle the accelerators for us.
- mii.fType = MFT_STRING;
- if (owner_draw_)
- mii.fType |= MFT_OWNERDRAW;
- // If the menu originally has radiocheck type, we should follow it.
- if (mii_info.fType & MFT_RADIOCHECK)
- mii.fType |= MFT_RADIOCHECK;
- mii.fState = GetStateFlagsForItemID(id);
-
- // Validate the label. If there is a contextual label, use it, otherwise
- // default to the static label
- string16 label;
- if (!delegate()->GetContextualLabel(id, &label))
- label = labels_[i - sep_count];
-
- if (owner_draw_) {
- item_data_[i - sep_count]->label = label;
- mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]);
- }
- mii.dwTypeData = const_cast<wchar_t*>(label.c_str());
- mii.cch = static_cast<UINT>(label.size());
- SetMenuItemInfo(menu_, i, true, &mii);
- } else {
- // Set data for owner drawn separators. Set dwItemData NULL to indicate
- // a separator.
- if (owner_draw_) {
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_FTYPE;
- mii.fType = MFT_SEPARATOR | MFT_OWNERDRAW;
- mii.dwItemData = NULL;
- SetMenuItemInfo(menu_, i, true, &mii);
- }
- ++sep_count;
- }
- }
-
- for (size_t i = 0; i < submenus_.size(); ++i)
- submenus_[i]->SetMenuInfo();
-}
-
-UINT MenuWin::GetStateFlagsForItemID(int item_id) const {
- // Use the delegate to get enabled and checked state.
- UINT flags =
- delegate()->IsCommandEnabled(item_id) ? MFS_ENABLED : MFS_DISABLED;
-
- if (delegate()->IsItemChecked(item_id))
- flags |= MFS_CHECKED;
-
- if (delegate()->IsItemDefault(item_id))
- flags |= MFS_DEFAULT;
-
- return flags;
-}
-
-DWORD MenuWin::GetTPMAlignFlags() const {
- // The manner in which we handle the menu alignment depends on whether or not
- // the menu is displayed within a mirrored view. If the UI is mirrored, the
- // alignment needs to be fliped so that instead of aligning the menu to the
- // right of the point, we align it to the left and vice versa.
- DWORD align_flags = TPM_TOPALIGN;
- switch (anchor()) {
- case TOPLEFT:
- if (delegate()->IsRightToLeftUILayout()) {
- align_flags |= TPM_RIGHTALIGN;
- } else {
- align_flags |= TPM_LEFTALIGN;
- }
- break;
-
- case TOPRIGHT:
- if (delegate()->IsRightToLeftUILayout()) {
- align_flags |= TPM_LEFTALIGN;
- } else {
- align_flags |= TPM_RIGHTALIGN;
- }
- break;
-
- default:
- NOTREACHED();
- return 0;
- }
- return align_flags;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_win.h b/chromium/ui/views/controls/menu/menu_win.h
deleted file mode 100644
index 284f26a4f85..00000000000
--- a/chromium/ui/views/controls/menu/menu_win.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_MENU_MENU_WIN_H_
-#define UI_VIEWS_CONTROLS_MENU_MENU_WIN_H_
-
-#include <windows.h>
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/views/controls/menu/menu.h"
-
-namespace views {
-
-namespace {
-class MenuHostWindow;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// Menu class
-//
-// A wrapper around a Win32 HMENU handle that provides convenient APIs for
-// menu construction, display and subsequent command execution.
-//
-///////////////////////////////////////////////////////////////////////////////
-class MenuWin : public Menu {
- public:
- // Construct a Menu using the specified controller to determine command
- // state.
- // delegate A Menu::Delegate implementation that provides more
- // information about the Menu presentation.
- // anchor An alignment hint for the popup menu.
- // owner The window that the menu is being brought up relative
- // to. Not actually used for anything but must not be
- // NULL.
- MenuWin(Delegate* d, AnchorPoint anchor, HWND owner);
- // Alternatively, a Menu object can be constructed wrapping an existing
- // HMENU. This can be used to use the convenience methods to insert
- // menu items and manage label string ownership. However this kind of
- // Menu object cannot use the delegate.
- explicit MenuWin(HMENU hmenu);
- virtual ~MenuWin();
-
- // Overridden from Menu:
- virtual void AddMenuItemWithIcon(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon) OVERRIDE;
- virtual Menu* AddSubMenuWithIcon(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon) OVERRIDE;
- virtual void AddSeparator(int index) OVERRIDE;
- virtual void EnableMenuItemByID(int item_id, bool enabled) OVERRIDE;
- virtual void EnableMenuItemAt(int index, bool enabled) OVERRIDE;
- virtual void SetMenuLabel(int item_id, const string16& label) OVERRIDE;
- virtual bool SetIcon(const gfx::ImageSkia& icon, int item_id) OVERRIDE;
- virtual void RunMenuAt(int x, int y) OVERRIDE;
- virtual void Cancel() OVERRIDE;
- virtual int ItemCount() OVERRIDE;
-
- virtual HMENU GetMenuHandle() const {
- return menu_;
- }
-
- // Gets the Win32 TPM alignment flags for the specified AnchorPoint.
- DWORD GetTPMAlignFlags() const;
-
- protected:
- virtual void AddMenuItemInternal(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon,
- MenuItemType type) OVERRIDE;
-
- private:
- friend class MenuHostWindow;
-
- // The data of menu items needed to display.
- struct ItemData;
-
- void AddMenuItemInternal(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon,
- HMENU submenu,
- MenuItemType type);
-
- explicit MenuWin(MenuWin* parent);
-
- // Sets menu information before displaying, including sub-menus.
- void SetMenuInfo();
-
- // Get all the state flags for the |fState| field of MENUITEMINFO for the
- // item with the specified id. |delegate| is consulted if non-NULL about
- // the state of the item in preference to |controller_|.
- UINT GetStateFlagsForItemID(int item_id) const;
-
- // The Win32 Menu Handle we wrap
- HMENU menu_;
-
- // The window that would receive WM_COMMAND messages when the user selects
- // an item from the menu.
- HWND owner_;
-
- // This list is used to store the default labels for the menu items.
- // We may use contextual labels when RunMenu is called, so we must save
- // a copy of default ones here.
- std::vector<string16> labels_;
-
- // A flag to indicate whether this menu will be drawn by the Menu class.
- // If it's true, all the menu items will be owner drawn. Otherwise,
- // all the drawing will be done by Windows.
- bool owner_draw_;
-
- // This list is to store the string labels and icons to display. It's used
- // when owner_draw_ is true. We give MENUITEMINFO pointers to these
- // structures to specify what we'd like to draw. If owner_draw_ is false,
- // we only give MENUITEMINFO pointers to the labels_.
- // The label member of the ItemData structure comes from either labels_ or
- // the GetContextualLabel.
- std::vector<ItemData*> item_data_;
-
- // Our sub-menus, if any.
- std::vector<MenuWin*> submenus_;
-
- // Whether the menu is visible.
- bool is_menu_visible_;
-
- DISALLOW_COPY_AND_ASSIGN(MenuWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_MENU_MENU_WIN_H_
diff --git a/chromium/ui/views/controls/menu/native_menu_win.cc b/chromium/ui/views/controls/menu/native_menu_win.cc
index c260af9bcce..caddd70c4a5 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.cc
+++ b/chromium/ui/views/controls/menu/native_menu_win.cc
@@ -18,10 +18,11 @@
#include "ui/base/models/menu_model.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/text_utils.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/native_theme/native_theme.h"
#include "ui/native_theme/native_theme_win.h"
@@ -51,7 +52,7 @@ struct NativeMenuWin::ItemData {
// The Windows API requires that whoever creates the menus must own the
// strings used for labels, and keep them around for the lifetime of the
// created menu. So be it.
- string16 label;
+ base::string16 label;
// Someone needs to own submenus, it may as well be us.
scoped_ptr<Menu2> submenu;
@@ -171,17 +172,18 @@ class NativeMenuWin::MenuHostWindow {
void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) {
NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData);
if (data) {
- gfx::Font font;
- measure_item_struct->itemWidth = font.GetStringWidth(data->label) +
+ gfx::FontList font_list;
+ measure_item_struct->itemWidth =
+ gfx::GetStringWidth(data->label, font_list) +
kIconWidth + kItemLeftMargin + views::kItemLabelSpacing -
GetSystemMetrics(SM_CXMENUCHECK);
if (data->submenu.get())
measure_item_struct->itemWidth += kArrowWidth;
// If the label contains an accelerator, make room for tab.
- if (data->label.find(L'\t') != string16::npos)
- measure_item_struct->itemWidth += font.GetStringWidth(L" ");
+ if (data->label.find(L'\t') != base::string16::npos)
+ measure_item_struct->itemWidth += gfx::GetStringWidth(L" ", font_list);
measure_item_struct->itemHeight =
- font.GetHeight() + kItemBottomMargin + kItemTopMargin;
+ font_list.GetHeight() + kItemBottomMargin + kItemTopMargin;
} else {
// Measure separator size.
measure_item_struct->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
@@ -225,19 +227,19 @@ class NativeMenuWin::MenuHostWindow {
SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
if (!underline_mnemonics)
format |= DT_HIDEPREFIX;
- gfx::Font font;
- HGDIOBJ old_font =
- static_cast<HFONT>(SelectObject(dc, font.GetNativeFont()));
+ gfx::FontList font_list;
+ HGDIOBJ old_font = static_cast<HFONT>(
+ SelectObject(dc, font_list.GetPrimaryFont().GetNativeFont()));
// If an accelerator is specified (with a tab delimiting the rest of the
// label from the accelerator), we have to justify the fist part on the
// left and the accelerator on the right.
// TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
// window system UI font and will not hit here.
- string16 label = data->label;
- string16 accel;
- string16::size_type tab_pos = label.find(L'\t');
- if (tab_pos != string16::npos) {
+ base::string16 label = data->label;
+ base::string16 accel;
+ base::string16::size_type tab_pos = label.find(L'\t');
+ if (tab_pos != base::string16::npos) {
accel = label.substr(tab_pos);
label = label.substr(0, tab_pos);
}
@@ -626,7 +628,7 @@ void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) {
mii.fType = MFT_OWNERDRAW;
ItemData* item_data = new ItemData;
- item_data->label = string16();
+ item_data->label = base::string16();
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
if (type == ui::MenuModel::TYPE_SUBMENU) {
item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
@@ -678,7 +680,7 @@ void NativeMenuWin::SetMenuItemState(int menu_index, bool enabled, bool checked,
void NativeMenuWin::SetMenuItemLabel(int menu_index,
int model_index,
- const string16& label) {
+ const base::string16& label) {
if (IsSeparatorItemAt(menu_index))
return;
@@ -690,8 +692,8 @@ void NativeMenuWin::SetMenuItemLabel(int menu_index,
void NativeMenuWin::UpdateMenuItemInfoForString(MENUITEMINFO* mii,
int model_index,
- const string16& label) {
- string16 formatted = label;
+ const base::string16& label) {
+ base::string16 formatted = label;
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
// Strip out any tabs, otherwise they get interpreted as accelerators and can
// lead to weird behavior.
diff --git a/chromium/ui/views/controls/menu/native_menu_win.h b/chromium/ui/views/controls/menu/native_menu_win.h
index ca6f37bc5c8..ce3a072e416 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.h
+++ b/chromium/ui/views/controls/menu/native_menu_win.h
@@ -74,7 +74,7 @@ class VIEWS_EXPORT NativeMenuWin : public MenuWrapper {
// Sets the label of the item at the specified index.
void SetMenuItemLabel(int menu_index,
int model_index,
- const string16& label);
+ const base::string16& label);
// Updates the local data structure with the correctly formatted version of
// |label| at the specified model_index, and adds string data to |mii| if
@@ -82,7 +82,7 @@ class VIEWS_EXPORT NativeMenuWin : public MenuWrapper {
// of the peculiarities of the Windows menu API.
void UpdateMenuItemInfoForString(MENUITEMINFO* mii,
int model_index,
- const string16& label);
+ const base::string16& label);
// Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
// supplied alignment and the UI text direction.
diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc
index 9184ca9abfb..a6ef56a888e 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -7,12 +7,14 @@
#include <algorithm>
#include "base/compiler_specific.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/controls/menu/menu_host.h"
+#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_scroll_view_container.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
@@ -41,7 +43,9 @@ SubmenuView::SubmenuView(MenuItemView* parent)
max_minor_text_width_(0),
minimum_preferred_width_(0),
resize_open_menu_(false),
- scroll_animator_(new ScrollAnimator(this)) {
+ scroll_animator_(new ScrollAnimator(this)),
+ roundoff_error_(0),
+ prefix_selector_(this) {
DCHECK(parent);
// We'll delete ourselves, otherwise the ScrollView would delete us on close.
set_owned_by_client();
@@ -117,7 +121,7 @@ void SubmenuView::Layout() {
}
}
-gfx::Size SubmenuView::GetPreferredSize() {
+gfx::Size SubmenuView::GetPreferredSize() const {
if (!has_children())
return gfx::Size();
@@ -128,11 +132,11 @@ gfx::Size SubmenuView::GetPreferredSize() {
int max_simple_width = 0;
int height = 0;
for (int i = 0; i < child_count(); ++i) {
- View* child = child_at(i);
+ const View* child = child_at(i);
if (!child->visible())
continue;
if (child->id() == MenuItemView::kMenuItemViewID) {
- MenuItemView* menu = static_cast<MenuItemView*>(child);
+ const MenuItemView* menu = static_cast<const MenuItemView*>(child);
const MenuItemView::MenuItemDimensions& dimensions =
menu->GetDimensions();
max_simple_width = std::max(
@@ -162,15 +166,20 @@ gfx::Size SubmenuView::GetPreferredSize() {
height + insets.height());
}
-void SubmenuView::GetAccessibleState(ui::AccessibleViewState* state) {
+void SubmenuView::GetAccessibleState(ui::AXViewState* state) {
// Inherit most of the state from the parent menu item, except the role.
if (GetMenuItem())
GetMenuItem()->GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_MENUPOPUP;
+ state->role = ui::AX_ROLE_MENU_LIST_POPUP;
+}
+
+ui::TextInputClient* SubmenuView::GetTextInputClient() {
+ return &prefix_selector_;
}
-void SubmenuView::PaintChildren(gfx::Canvas* canvas) {
- View::PaintChildren(canvas);
+void SubmenuView::PaintChildren(gfx::Canvas* canvas,
+ const views::CullSet& cull_set) {
+ View::PaintChildren(canvas, cull_set);
if (drop_item_ && drop_position_ != MenuDelegate::DROP_ON)
PaintDropIndicator(canvas, drop_item_, drop_position_);
@@ -293,6 +302,35 @@ void SubmenuView::OnGestureEvent(ui::GestureEvent* event) {
event->SetHandled();
}
+int SubmenuView::GetRowCount() {
+ return GetMenuItemCount();
+}
+
+int SubmenuView::GetSelectedRow() {
+ int row = 0;
+ for (int i = 0; i < child_count(); ++i) {
+ if (child_at(i)->id() != MenuItemView::kMenuItemViewID)
+ continue;
+
+ if (static_cast<MenuItemView*>(child_at(i))->IsSelected())
+ return row;
+
+ row++;
+ }
+
+ return -1;
+}
+
+void SubmenuView::SetSelectedRow(int row) {
+ GetMenuItem()->GetMenuController()->SetSelection(
+ GetMenuItemAt(row),
+ MenuController::SELECTION_DEFAULT);
+}
+
+base::string16 SubmenuView::GetTextForRow(int row) {
+ return GetMenuItemAt(row)->title();
+}
+
bool SubmenuView::IsShowing() {
return host_ && host_->IsMenuHostVisible();
}
@@ -313,10 +351,10 @@ void SubmenuView::ShowAt(Widget* parent,
}
GetScrollViewContainer()->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_MENUSTART,
+ ui::AX_EVENT_MENU_START,
true);
NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_MENUPOPUPSTART,
+ ui::AX_EVENT_MENU_POPUP_START,
true);
}
@@ -327,9 +365,9 @@ void SubmenuView::Reposition(const gfx::Rect& bounds) {
void SubmenuView::Close() {
if (host_) {
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_MENUPOPUPEND, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_MENU_POPUP_END, true);
GetScrollViewContainer()->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_MENUEND, true);
+ ui::AX_EVENT_MENU_END, true);
host_->DestroyMenuHost();
host_ = NULL;
@@ -446,7 +484,9 @@ bool SubmenuView::OnScroll(float dx, float dy) {
const gfx::Rect& vis_bounds = GetVisibleBounds();
const gfx::Rect& full_bounds = bounds();
int x = vis_bounds.x();
- int y = vis_bounds.y() - static_cast<int>(dy);
+ float y_f = vis_bounds.y() - dy - roundoff_error_;
+ int y = gfx::ToRoundedInt(y_f);
+ roundoff_error_ = y - y_f;
// clamp y to [0, full_height - vis_height)
y = std::min(y, full_bounds.height() - vis_bounds.height() - 1);
y = std::max(y, 0);
diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h
index 19e0d46ffa2..1b7d36243d2 100644
--- a/chromium/ui/views/controls/menu/submenu_view.h
+++ b/chromium/ui/views/controls/menu/submenu_view.h
@@ -10,6 +10,8 @@
#include "base/compiler_specific.h"
#include "ui/views/animation/scroll_animator.h"
#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/views/controls/prefix_delegate.h"
+#include "ui/views/controls/prefix_selector.h"
#include "ui/views/view.h"
namespace views {
@@ -26,14 +28,14 @@ class MenuScrollViewContainer;
// . Forwards the appropriate events to the MenuController. This allows the
// MenuController to update the selection as the user moves the mouse around.
// . Renders the drop indicator during a drop operation.
-// . Shows and hides the window (a NativeWidgetWin) when the menu is shown on
+// . Shows and hides the window (a NativeWidget) when the menu is shown on
// screen.
//
// SubmenuView is itself contained in a MenuScrollViewContainer.
// MenuScrollViewContainer handles showing as much of the SubmenuView as the
// screen allows. If the SubmenuView is taller than the screen, scroll buttons
// are provided that allow the user to see all the menu items.
-class VIEWS_EXPORT SubmenuView : public View,
+class VIEWS_EXPORT SubmenuView : public PrefixDelegate,
public ScrollDelegate {
public:
// The submenu's class name.
@@ -53,13 +55,15 @@ class VIEWS_EXPORT SubmenuView : public View,
// Positions and sizes the child views. This tiles the views vertically,
// giving each child the available width.
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Override from View.
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
// Painting.
- virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
+ virtual void PaintChildren(gfx::Canvas* canvas,
+ const views::CullSet& cull_view) OVERRIDE;
// Drag and drop methods. These are forwarded to the MenuController.
virtual bool GetDropFormats(
@@ -79,6 +83,12 @@ class VIEWS_EXPORT SubmenuView : public View,
// Scrolls on menu item boundaries.
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+ // Overridden from PrefixDelegate.
+ virtual int GetRowCount() OVERRIDE;
+ virtual int GetSelectedRow() OVERRIDE;
+ virtual void SetSelectedRow(int row) OVERRIDE;
+ virtual base::string16 GetTextForRow(int row) OVERRIDE;
+
// Returns true if the menu is showing.
bool IsShowing();
@@ -191,7 +201,7 @@ class VIEWS_EXPORT SubmenuView : public View,
MenuScrollViewContainer* scroll_view_container_;
// See description above getter.
- int max_minor_text_width_;
+ mutable int max_minor_text_width_;
// Minimum width returned in GetPreferredSize().
int minimum_preferred_width_;
@@ -202,6 +212,14 @@ class VIEWS_EXPORT SubmenuView : public View,
// The submenu's scroll animator
scoped_ptr<ScrollAnimator> scroll_animator_;
+ // Difference between current position and cumulative deltas passed to
+ // OnScroll.
+ // TODO(tdresser): This should be removed when raw pixel scrolling for views
+ // is enabled. See crbug.com/329354.
+ float roundoff_error_;
+
+ PrefixSelector prefix_selector_;
+
DISALLOW_COPY_AND_ASSIGN(SubmenuView);
};
diff --git a/chromium/ui/views/controls/message_box_view.cc b/chromium/ui/views/controls/message_box_view.cc
index 3c2cde95292..671ca6194ec 100644
--- a/chromium/ui/views/controls/message_box_view.cc
+++ b/chromium/ui/views/controls/message_box_view.cc
@@ -8,7 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/views/controls/button/checkbox.h"
@@ -36,7 +36,7 @@ const int kDefaultMessageWidth = 320;
// 001C..001E ; B # Cc [3] <control-001C>..<control-001E>
// 0085 ; B # Cc <control-0085>
// 2029 ; B # Zp PARAGRAPH SEPARATOR
-bool IsParagraphSeparator(char16 c) {
+bool IsParagraphSeparator(base::char16 c) {
return ( c == 0x000A || c == 0x000D || c == 0x001C || c == 0x001D ||
c == 0x001E || c == 0x0085 || c == 0x2029);
}
@@ -44,8 +44,8 @@ bool IsParagraphSeparator(char16 c) {
// Splits |text| into a vector of paragraphs.
// Given an example "\nabc\ndef\n\n\nhij\n", the split results should be:
// "", "abc", "def", "", "", "hij", and "".
-void SplitStringIntoParagraphs(const string16& text,
- std::vector<string16>* paragraphs) {
+void SplitStringIntoParagraphs(const base::string16& text,
+ std::vector<base::string16>* paragraphs) {
paragraphs->clear();
size_t start = 0;
@@ -65,7 +65,7 @@ namespace views {
///////////////////////////////////////////////////////////////////////////////
// MessageBoxView, public:
-MessageBoxView::InitParams::InitParams(const string16& message)
+MessageBoxView::InitParams::InitParams(const base::string16& message)
: options(NO_OPTIONS),
message(message),
message_width(kDefaultMessageWidth),
@@ -85,8 +85,8 @@ MessageBoxView::MessageBoxView(const InitParams& params)
MessageBoxView::~MessageBoxView() {}
-string16 MessageBoxView::GetInputText() {
- return prompt_field_ ? prompt_field_->text() : string16();
+base::string16 MessageBoxView::GetInputText() {
+ return prompt_field_ ? prompt_field_->text() : base::string16();
}
bool MessageBoxView::IsCheckBoxSelected() {
@@ -101,7 +101,7 @@ void MessageBoxView::SetIcon(const gfx::ImageSkia& icon) {
ResetLayoutManager();
}
-void MessageBoxView::SetCheckBoxLabel(const string16& label) {
+void MessageBoxView::SetCheckBoxLabel(const base::string16& label) {
if (!checkbox_)
checkbox_ = new Checkbox(label);
else
@@ -115,7 +115,8 @@ void MessageBoxView::SetCheckBoxSelected(bool selected) {
checkbox_->SetChecked(selected);
}
-void MessageBoxView::SetLink(const string16& text, LinkListener* listener) {
+void MessageBoxView::SetLink(const base::string16& text,
+ LinkListener* listener) {
if (text.empty()) {
DCHECK(!listener);
delete link_;
@@ -132,8 +133,8 @@ void MessageBoxView::SetLink(const string16& text, LinkListener* listener) {
ResetLayoutManager();
}
-void MessageBoxView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_ALERT;
+void MessageBoxView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_ALERT;
}
///////////////////////////////////////////////////////////////////////////////
@@ -145,7 +146,7 @@ void MessageBoxView::ViewHierarchyChanged(
if (prompt_field_)
prompt_field_->SelectAll(true);
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_ALERT, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
}
}
@@ -162,7 +163,7 @@ bool MessageBoxView::AcceleratorPressed(const ui::Accelerator& accelerator) {
return false;
ui::ScopedClipboardWriter scw(clipboard, ui::CLIPBOARD_TYPE_COPY_PASTE);
- string16 text = message_labels_[0]->text();
+ base::string16 text = message_labels_[0]->text();
for (size_t i = 1; i < message_labels_.size(); ++i)
text += message_labels_[i]->text();
scw.WriteText(text);
@@ -174,23 +175,15 @@ bool MessageBoxView::AcceleratorPressed(const ui::Accelerator& accelerator) {
void MessageBoxView::Init(const InitParams& params) {
if (params.options & DETECT_DIRECTIONALITY) {
- std::vector<string16> texts;
+ 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 {
diff --git a/chromium/ui/views/controls/message_box_view.h b/chromium/ui/views/controls/message_box_view.h
index 1d92a379be4..cb708e6013d 100644
--- a/chromium/ui/views/controls/message_box_view.h
+++ b/chromium/ui/views/controls/message_box_view.h
@@ -42,12 +42,12 @@ class VIEWS_EXPORT MessageBoxView : public View {
};
struct VIEWS_EXPORT InitParams {
- explicit InitParams(const string16& message);
+ explicit InitParams(const base::string16& message);
~InitParams();
uint16 options;
- string16 message;
- string16 default_prompt;
+ base::string16 message;
+ base::string16 default_prompt;
int message_width;
int inter_row_vertical_spacing;
};
@@ -60,7 +60,7 @@ class VIEWS_EXPORT MessageBoxView : public View {
views::Textfield* text_box() { return prompt_field_; }
// Returns user entered data in the prompt field.
- string16 GetInputText();
+ base::string16 GetInputText();
// Returns true if a checkbox is selected, false otherwise. (And false if
// the message box has no checkbox.)
@@ -73,17 +73,17 @@ class VIEWS_EXPORT MessageBoxView : public View {
// Adds a checkbox with the specified label to the message box if this is the
// first call. Otherwise, it changes the label of the current checkbox. To
// start, the message box has no checkbox until this function is called.
- void SetCheckBoxLabel(const string16& label);
+ void SetCheckBoxLabel(const base::string16& label);
// Sets the state of the check-box.
void SetCheckBoxSelected(bool selected);
// Sets the text and the listener of the link. If |text| is empty, the link
// is removed.
- void SetLink(const string16& text, LinkListener* listener);
+ void SetLink(const base::string16& text, LinkListener* listener);
// View:
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// View:
diff --git a/chromium/ui/views/controls/native/native_view_host.cc b/chromium/ui/views/controls/native/native_view_host.cc
index 28b1fe3aec7..c1b230c452e 100644
--- a/chromium/ui/views/controls/native/native_view_host.cc
+++ b/chromium/ui/views/controls/native/native_view_host.cc
@@ -5,6 +5,7 @@
#include "ui/views/controls/native/native_view_host.h"
#include "base/logging.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
#include "ui/views/accessibility/native_view_accessibility.h"
#include "ui/views/controls/native/native_view_host_wrapper.h"
@@ -16,16 +17,6 @@ namespace views {
const char NativeViewHost::kViewClassName[] = "NativeViewHost";
const char kWidgetNativeViewHostKey[] = "WidgetNativeViewHost";
-#if defined(USE_AURA)
-// Views implementation draws the focus.
-// TODO(oshima): Eliminate this flag and consolidate
-// the focus border code.
-const bool NativeViewHost::kRenderNativeControlFocus = false;
-#else
-// static
-const bool NativeViewHost::kRenderNativeControlFocus = true;
-#endif
-
////////////////////////////////////////////////////////////////////////////////
// NativeViewHost, public:
@@ -74,7 +65,7 @@ void NativeViewHost::NativeViewDestroyed() {
////////////////////////////////////////////////////////////////////////////////
// NativeViewHost, View overrides:
-gfx::Size NativeViewHost::GetPreferredSize() {
+gfx::Size NativeViewHost::GetPreferredSize() const {
return preferred_size_;
}
@@ -182,7 +173,7 @@ const char* NativeViewHost::GetClassName() const {
void NativeViewHost::OnFocus() {
native_wrapper_->SetFocus();
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
gfx::NativeViewAccessible NativeViewHost::GetNativeViewAccessible() {
@@ -196,6 +187,10 @@ gfx::NativeViewAccessible NativeViewHost::GetNativeViewAccessible() {
return View::GetNativeViewAccessible();
}
+gfx::NativeCursor NativeViewHost::GetCursor(const ui::MouseEvent& event) {
+ return native_wrapper_->GetCursor(event.x(), event.y());
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeViewHost, private:
@@ -226,5 +221,4 @@ void NativeViewHost::ClearFocus() {
}
}
-
} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host.h b/chromium/ui/views/controls/native/native_view_host.h
index bdc51510550..d5dd9b59fdb 100644
--- a/chromium/ui/views/controls/native/native_view_host.h
+++ b/chromium/ui/views/controls/native/native_view_host.h
@@ -28,9 +28,6 @@ class VIEWS_EXPORT NativeViewHost : public View {
// The NativeViewHost's class name.
static const char kViewClassName[];
- // Should views render the focus when on native controls?
- static const bool kRenderNativeControlFocus;
-
NativeViewHost();
virtual ~NativeViewHost();
@@ -80,12 +77,13 @@ class VIEWS_EXPORT NativeViewHost : public View {
void NativeViewDestroyed();
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
+ virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
protected:
virtual bool NeedsNotificationWhenVisibleBoundsChange() const OVERRIDE;
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.cc b/chromium/ui/views/controls/native/native_view_host_aura.cc
index a71e230be47..49bf733bbe2 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/view_constants_aura.h"
#include "ui/views/widget/widget.h"
@@ -100,6 +101,12 @@ gfx::NativeViewAccessible NativeViewHostAura::GetNativeViewAccessible() {
return NULL;
}
+gfx::NativeCursor NativeViewHostAura::GetCursor(int x, int y) {
+ if (host_->native_view())
+ return host_->native_view()->GetCursor(gfx::Point(x, y));
+ return gfx::kNullCursor;
+}
+
void NativeViewHostAura::OnWindowDestroyed(aura::Window* window) {
DCHECK(window == host_->native_view());
host_->NativeViewDestroyed();
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.h b/chromium/ui/views/controls/native/native_view_host_aura.h
index eba4b99c9fd..8ef4e455f3d 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.h
+++ b/chromium/ui/views/controls/native/native_view_host_aura.h
@@ -34,6 +34,7 @@ class VIEWS_EXPORT NativeViewHostAura : public NativeViewHostWrapper,
virtual void HideWidget() OVERRIDE;
virtual void SetFocus() OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
+ virtual gfx::NativeCursor GetCursor(int x, int y) OVERRIDE;
private:
// Overridden from aura::WindowObserver:
diff --git a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
index 7653cc905c3..f6dc561f2f0 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/aura/window.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
@@ -24,6 +25,10 @@ class NativeViewHostAuraTest : public ViewsTestBase {
return static_cast<NativeViewHostAura*>(host_->native_wrapper_.get());
}
+ Widget* toplevel() {
+ return toplevel_.get();
+ }
+
NativeViewHost* host() {
return host_.get();
}
@@ -95,4 +100,18 @@ TEST_F(NativeViewHostAuraTest, HostViewPropertyKey) {
EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
}
+// Tests that the NativeViewHost reports the cursor set on its native view.
+TEST_F(NativeViewHostAuraTest, CursorForNativeView) {
+ CreateHost();
+
+ toplevel()->SetCursor(ui::kCursorHand);
+ child()->SetCursor(ui::kCursorWait);
+ ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
+ gfx::Point(0, 0), 0, 0);
+
+ EXPECT_EQ(ui::kCursorWait, host()->GetCursor(move_event).native_type());
+
+ DestroyHost();
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host_mac.cc b/chromium/ui/views/controls/native/native_view_host_mac.cc
new file mode 100644
index 00000000000..53bb00b7a0e
--- /dev/null
+++ b/chromium/ui/views/controls/native/native_view_host_mac.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/native/native_view_host_wrapper.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeViewHostWrapper, public:
+
+// static
+NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper(
+ NativeViewHost* host) {
+ return NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host_unittest.cc b/chromium/ui/views/controls/native/native_view_host_unittest.cc
index f30980bca8b..247782437a5 100644
--- a/chromium/ui/views/controls/native/native_view_host_unittest.cc
+++ b/chromium/ui/views/controls/native/native_view_host_unittest.cc
@@ -4,19 +4,12 @@
#include "ui/views/controls/native/native_view_host.h"
-#if defined(OS_WIN) && !defined(USE_AURA)
-#include <windows.h>
-#endif
-
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/aura/window.h"
-#endif
-
namespace views {
class NativeViewHostTest : public ViewsTestBase {
@@ -93,15 +86,9 @@ class NativeViewHierarchyChangedTestView : public View {
DISALLOW_COPY_AND_ASSIGN(NativeViewHierarchyChangedTestView);
};
-#if defined(USE_AURA)
aura::Window* GetNativeParent(aura::Window* window) {
return window->parent();
}
-#elif defined(OS_WIN)
-HWND GetNativeParent(HWND window) {
- return GetParent(window);
-}
-#endif
class ViewHierarchyChangedTestHost : public NativeViewHost {
public:
diff --git a/chromium/ui/views/controls/native/native_view_host_win.cc b/chromium/ui/views/controls/native/native_view_host_win.cc
deleted file mode 100644
index e7b74c3c7a1..00000000000
--- a/chromium/ui/views/controls/native/native_view_host_win.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/native/native_view_host_win.h"
-
-#include <oleacc.h>
-
-#include "base/logging.h"
-#include "ui/base/win/hidden_window.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/gfx/win/window_impl.h"
-#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/widget/native_widget.h"
-#include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeViewHostWin, public:
-
-NativeViewHostWin::NativeViewHostWin(NativeViewHost* host)
- : host_(host),
- installed_clip_(false) {
-}
-
-NativeViewHostWin::~NativeViewHostWin() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeViewHostWin, NativeViewHostWrapper implementation:
-void NativeViewHostWin::NativeViewWillAttach() {
- // First hide the new window. We don't want anything to draw (like sub-hwnd
- // borders), when NativeViewHost changes the parent.
- ShowWindow(host_->native_view(), SW_HIDE);
-}
-
-void NativeViewHostWin::NativeViewDetaching(bool destroyed) {
- if (!destroyed) {
- if (installed_clip_)
- UninstallClip();
- Widget::ReparentNativeView(host_->native_view(), ui::GetHiddenWindow());
- }
- installed_clip_ = false;
-}
-
-void NativeViewHostWin::AddedToWidget() {
- if (!IsWindow(host_->native_view()))
- return;
- HWND parent_hwnd = GetParent(host_->native_view());
- HWND widget_hwnd = host_->GetWidget()->GetNativeView();
- if (parent_hwnd != widget_hwnd)
- SetParent(host_->native_view(), widget_hwnd);
- if (host_->IsDrawn())
- ShowWindow(host_->native_view(), SW_SHOW);
- else
- ShowWindow(host_->native_view(), SW_HIDE);
- host_->Layout();
-}
-
-void NativeViewHostWin::RemovedFromWidget() {
- if (!IsWindow(host_->native_view()))
- return;
- ShowWindow(host_->native_view(), SW_HIDE);
- SetParent(host_->native_view(), NULL);
-}
-
-void NativeViewHostWin::InstallClip(int x, int y, int w, int h) {
- HRGN clip_region = CreateRectRgn(x, y, x + w, y + h);
- // NOTE: SetWindowRgn owns the region (as well as the deleting the
- // current region), as such we don't delete the old region.
- SetWindowRgn(host_->native_view(), clip_region, TRUE);
- installed_clip_ = true;
-}
-
-bool NativeViewHostWin::HasInstalledClip() {
- return installed_clip_;
-}
-
-void NativeViewHostWin::UninstallClip() {
- SetWindowRgn(host_->native_view(), 0, TRUE);
- installed_clip_ = false;
-}
-
-void NativeViewHostWin::ShowWidget(int x, int y, int w, int h) {
- UINT swp_flags = SWP_DEFERERASE |
- SWP_NOACTIVATE |
- SWP_NOCOPYBITS |
- SWP_NOOWNERZORDER |
- SWP_NOZORDER;
- gfx::Rect bounds = gfx::win::DIPToScreenRect(gfx::Rect(x,y,w,h));
-
- // Only send the SHOWWINDOW flag if we're invisible, to avoid flashing.
- if (!IsWindowVisible(host_->native_view()))
- swp_flags = (swp_flags | SWP_SHOWWINDOW) & ~SWP_NOREDRAW;
-
- if (host_->fast_resize()) {
- // In a fast resize, we move the window and clip it with SetWindowRgn.
- RECT win_rect;
- GetWindowRect(host_->native_view(), &win_rect);
- gfx::Rect rect(win_rect);
- SetWindowPos(host_->native_view(), 0, bounds.x(), bounds.y(),
- rect.width(), rect.height(),
- swp_flags);
-
- InstallClip(0, 0, bounds.width(), bounds.height());
- } else {
- SetWindowPos(host_->native_view(), 0, bounds.x(), bounds.y(),
- bounds.width(), bounds.height(), swp_flags);
- }
-}
-
-void NativeViewHostWin::HideWidget() {
- if (!IsWindowVisible(host_->native_view()))
- return; // Currently not visible, nothing to do.
-
- // The window is currently visible, but its clipped by another view. Hide
- // it.
- SetWindowPos(host_->native_view(), 0, 0, 0, 0, 0,
- SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER |
- SWP_NOREDRAW | SWP_NOOWNERZORDER);
-}
-
-void NativeViewHostWin::SetFocus() {
- ::SetFocus(host_->native_view());
-}
-
-gfx::NativeViewAccessible NativeViewHostWin::GetNativeViewAccessible() {
- HWND hwnd = host_->native_view();
- if (!IsWindow(hwnd))
- return NULL;
-
- IAccessible* accessible = NULL;
- HRESULT success = ::AccessibleObjectFromWindow(
- hwnd, OBJID_CLIENT, IID_IAccessible,
- reinterpret_cast<void**>(&accessible));
-
- if (success == S_OK) {
- return accessible;
- } else {
- return NULL;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeViewHostWrapper, public:
-
-// static
-NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper(
- NativeViewHost* host) {
- return new NativeViewHostWin(host);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host_win.h b/chromium/ui/views/controls/native/native_view_host_win.h
deleted file mode 100644
index ea94b351ea3..00000000000
--- a/chromium/ui/views/controls/native/native_view_host_win.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_WIN_H_
-#define UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_WIN_H_
-
-#include "base/basictypes.h"
-#include "ui/views/controls/native/native_view_host_wrapper.h"
-
-namespace views {
-
-class NativeViewHost;
-
-// A Windows implementation of NativeViewHostWrapper
-class NativeViewHostWin : public NativeViewHostWrapper {
- public:
- explicit NativeViewHostWin(NativeViewHost* host);
- virtual ~NativeViewHostWin();
-
- // Overridden from NativeViewHostWrapper:
- virtual void NativeViewWillAttach();
- virtual void NativeViewDetaching(bool destroyed);
- virtual void AddedToWidget();
- virtual void RemovedFromWidget();
- virtual void InstallClip(int x, int y, int w, int h);
- virtual bool HasInstalledClip();
- virtual void UninstallClip();
- virtual void ShowWidget(int x, int y, int w, int h);
- virtual void HideWidget();
- virtual void SetFocus();
- virtual gfx::NativeViewAccessible GetNativeViewAccessible();
-
- private:
- // Our associated NativeViewHost.
- NativeViewHost* host_;
-
- // Have we installed a region on the gfx::NativeView used to clip to only the
- // visible portion of the gfx::NativeView ?
- bool installed_clip_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeViewHostWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_WIN_H_
diff --git a/chromium/ui/views/controls/native/native_view_host_wrapper.h b/chromium/ui/views/controls/native/native_view_host_wrapper.h
index 3b3cb37fbdc..306aa0148bb 100644
--- a/chromium/ui/views/controls/native/native_view_host_wrapper.h
+++ b/chromium/ui/views/controls/native/native_view_host_wrapper.h
@@ -62,6 +62,10 @@ class VIEWS_EXPORT NativeViewHostWrapper {
// view.
virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
+ // Returns the native cursor corresponding to the point (x, y)
+ // in the native view.
+ virtual gfx::NativeCursor GetCursor(int x, int y) = 0;
+
// Creates a platform-specific instance of an object implementing this
// interface.
static NativeViewHostWrapper* CreateWrapper(NativeViewHost* host);
diff --git a/chromium/ui/views/controls/native_control.cc b/chromium/ui/views/controls/native_control.cc
deleted file mode 100644
index faebbc81f90..00000000000
--- a/chromium/ui/views/controls/native_control.cc
+++ /dev/null
@@ -1,389 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/native_control.h"
-
-#include <atlbase.h>
-#include <atlapp.h>
-#include <atlcrack.h>
-#include <atlframe.h>
-#include <atlmisc.h>
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/base/accessibility/accessibility_types.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/base/view_prop.h"
-#include "ui/events/keycodes/keyboard_code_conversion_win.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/widget/widget.h"
-
-using ui::ViewProp;
-
-namespace views {
-
-// Maps to the NativeControl.
-static const char* const kNativeControlKey = "__NATIVE_CONTROL__";
-
-class NativeControlContainer : public CWindowImpl<NativeControlContainer,
- CWindow,
- CWinTraits<WS_CHILD | WS_CLIPSIBLINGS |
- WS_CLIPCHILDREN>> {
- public:
- explicit NativeControlContainer(NativeControl* parent)
- : parent_(parent),
- control_(NULL),
- original_handler_(NULL) {
- }
-
- void Init() {
- Create(parent_->GetWidget()->GetNativeView());
- ::ShowWindow(m_hWnd, SW_SHOW);
- }
-
- virtual ~NativeControlContainer() {
- }
-
- // NOTE: If you add a new message, be sure and verify parent_ is valid before
- // calling into parent_.
- DECLARE_FRAME_WND_CLASS(L"ChromeViewsNativeControlContainer", NULL);
- BEGIN_MSG_MAP(NativeControlContainer);
- MSG_WM_CREATE(OnCreate);
- MSG_WM_ERASEBKGND(OnEraseBkgnd);
- MSG_WM_PAINT(OnPaint);
- MSG_WM_SIZE(OnSize);
- MSG_WM_NOTIFY(OnNotify);
- MSG_WM_COMMAND(OnCommand);
- MSG_WM_DESTROY(OnDestroy);
- MSG_WM_CONTEXTMENU(OnContextMenu);
- MSG_WM_CTLCOLORBTN(OnCtlColorBtn);
- MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic)
- END_MSG_MAP();
-
- HWND GetControl() {
- return control_;
- }
-
- // Called when the parent is getting deleted. This control stays around until
- // it gets the OnFinalMessage call.
- void ResetParent() {
- parent_ = NULL;
- }
-
- void OnFinalMessage(HWND hwnd) {
- if (parent_)
- parent_->NativeControlDestroyed();
- delete this;
- }
-
- private:
- friend class NativeControl;
-
- LRESULT OnCreate(LPCREATESTRUCT create_struct) {
- control_ = parent_->CreateNativeControl(m_hWnd);
-
- // We subclass the control hwnd so we get the WM_KEYDOWN messages.
- original_handler_ = gfx::SetWindowProc(
- control_, &NativeControl::NativeControlWndProc);
- prop_.reset(new ViewProp(control_, kNativeControlKey , parent_));
-
- ::ShowWindow(control_, SW_SHOW);
- return 1;
- }
-
- LRESULT OnEraseBkgnd(HDC dc) {
- return 1;
- }
-
- void OnPaint(HDC ignore) {
- PAINTSTRUCT ps;
- HDC dc = ::BeginPaint(*this, &ps);
- ::EndPaint(*this, &ps);
- }
-
- void OnSize(int type, const CSize& sz) {
- ::MoveWindow(control_, 0, 0, sz.cx, sz.cy, TRUE);
- }
-
- LRESULT OnCommand(UINT code, int id, HWND source) {
- return parent_ ? parent_->OnCommand(code, id, source) : 0;
- }
-
- LRESULT OnNotify(int w_param, LPNMHDR l_param) {
- if (parent_)
- return parent_->OnNotify(w_param, l_param);
- else
- return 0;
- }
-
- void OnDestroy() {
- if (parent_)
- parent_->OnDestroy();
- }
-
- void OnContextMenu(HWND window, const POINT& location) {
- if (parent_)
- parent_->OnContextMenu(location);
- }
-
- // We need to find an ancestor with a non-null background, and
- // ask it for a (solid color) brush that approximates
- // the background. The caller will use this when drawing
- // the native control as a background color, particularly
- // for radiobuttons and XP style pushbuttons.
- LRESULT OnCtlColor(UINT msg, HDC dc, HWND control) {
- const View *ancestor = parent_;
- while (ancestor) {
- const Background *background = ancestor->background();
- if (background) {
- HBRUSH brush = background->GetNativeControlBrush();
- if (brush)
- return reinterpret_cast<LRESULT>(brush);
- }
- ancestor = ancestor->parent();
- }
-
- // COLOR_BTNFACE is the default for dialog box backgrounds.
- return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE));
- }
-
- LRESULT OnCtlColorBtn(HDC dc, HWND control) {
- return OnCtlColor(WM_CTLCOLORBTN, dc, control);
- }
-
- LRESULT OnCtlColorStatic(HDC dc, HWND control) {
- return OnCtlColor(WM_CTLCOLORSTATIC, dc, control);
- }
-
- NativeControl* parent_;
- HWND control_;
-
- // Message handler that was set before we reset it.
- WNDPROC original_handler_;
-
- scoped_ptr<ViewProp> prop_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeControlContainer);
-};
-
-NativeControl::NativeControl() : hwnd_view_(NULL),
- container_(NULL),
- fixed_width_(-1),
- horizontal_alignment_(CENTER),
- fixed_height_(-1),
- vertical_alignment_(CENTER) {
- SetFocusable(true);
-}
-
-NativeControl::~NativeControl() {
- if (container_) {
- container_->ResetParent();
- ::DestroyWindow(*container_);
- }
-}
-
-void NativeControl::ValidateNativeControl() {
- if (hwnd_view_ == NULL) {
- hwnd_view_ = new NativeViewHost;
- AddChildView(hwnd_view_);
- }
-
- if (!container_ && visible()) {
- container_ = new NativeControlContainer(this);
- container_->Init();
- hwnd_view_->Attach(*container_);
- if (!enabled())
- EnableWindow(GetNativeControlHWND(), enabled());
-
- // This message ensures that the focus border is shown.
- ::SendMessage(container_->GetControl(),
- WM_CHANGEUISTATE,
- MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS),
- 0);
- }
-}
-
-void NativeControl::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- if (details.is_add && details.parent != this && !container_ && GetWidget()) {
- ValidateNativeControl();
- Layout();
- }
-}
-
-void NativeControl::Layout() {
- if (!container_ && GetWidget())
- ValidateNativeControl();
-
- if (hwnd_view_) {
- gfx::Rect lb = GetLocalBounds();
-
- int x = lb.x();
- int y = lb.y();
- int width = lb.width();
- int height = lb.height();
- if (fixed_width_ > 0) {
- width = std::min(fixed_width_, width);
- switch (horizontal_alignment_) {
- case LEADING:
- // Nothing to do.
- break;
- case CENTER:
- x += (lb.width() - width) / 2;
- break;
- case TRAILING:
- x = x + lb.width() - width;
- break;
- default:
- NOTREACHED();
- }
- }
-
- if (fixed_height_ > 0) {
- height = std::min(fixed_height_, height);
- switch (vertical_alignment_) {
- case LEADING:
- // Nothing to do.
- break;
- case CENTER:
- y += (lb.height() - height) / 2;
- break;
- case TRAILING:
- y = y + lb.height() - height;
- break;
- default:
- NOTREACHED();
- }
- }
-
- hwnd_view_->SetBounds(x, y, width, height);
- }
-}
-
-void NativeControl::OnContextMenu(const POINT& location) {
- if (!context_menu_controller())
- return;
-
- if (location.x == -1 && location.y == -1) {
- ShowContextMenu(GetKeyboardContextMenuLocation(),
- ui::MENU_SOURCE_KEYBOARD);
- } else {
- ShowContextMenu(gfx::Point(location), ui::MENU_SOURCE_MOUSE);
- }
-}
-
-void NativeControl::OnFocus() {
- if (container_) {
- DCHECK(container_->GetControl());
- ::SetFocus(container_->GetControl());
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, false);
- }
-}
-
-HWND NativeControl::GetNativeControlHWND() {
- if (container_)
- return container_->GetControl();
- else
- return NULL;
-}
-
-void NativeControl::NativeControlDestroyed() {
- if (hwnd_view_)
- hwnd_view_->Detach();
- container_ = NULL;
-}
-
-void NativeControl::SetVisible(bool is_visible) {
- if (is_visible != visible()) {
- View::SetVisible(is_visible);
- if (!is_visible && container_)
- ::DestroyWindow(*container_);
- else if (is_visible && !container_)
- ValidateNativeControl();
- }
-}
-
-void NativeControl::OnEnabledChanged() {
- View::OnEnabledChanged();
- if (GetNativeControlHWND())
- EnableWindow(GetNativeControlHWND(), enabled());
-}
-
-void NativeControl::OnPaint(gfx::Canvas* canvas) {
-}
-
-void NativeControl::VisibilityChanged(View* starting_from, bool is_visible) {
- SetVisible(is_visible);
-}
-
-void NativeControl::SetFixedWidth(int width, Alignment alignment) {
- DCHECK_GT(width, 0);
- fixed_width_ = width;
- horizontal_alignment_ = alignment;
-}
-
-void NativeControl::SetFixedHeight(int height, Alignment alignment) {
- DCHECK_GT(height, 0);
- fixed_height_ = height;
- vertical_alignment_ = alignment;
-}
-
-DWORD NativeControl::GetAdditionalExStyle() const {
- // If the UI for the view is mirrored, we should make sure we add the
- // extended window style for a right-to-left layout so the subclass creates
- // a mirrored HWND for the underlying control.
- DWORD ex_style = 0;
- if (base::i18n::IsRTL())
- ex_style |= l10n_util::GetExtendedStyles();
-
- return ex_style;
-}
-
-DWORD NativeControl::GetAdditionalRTLStyle() const {
- // If the UI for the view is mirrored, we should make sure we add the
- // extended window style for a right-to-left layout so the subclass creates
- // a mirrored HWND for the underlying control.
- DWORD ex_style = 0;
- if (base::i18n::IsRTL())
- ex_style |= l10n_util::GetExtendedTooltipStyles();
-
- return ex_style;
-}
-
-// static
-LRESULT CALLBACK NativeControl::NativeControlWndProc(HWND window,
- UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- NativeControl* native_control = static_cast<NativeControl*>(
- ViewProp::GetValue(window, kNativeControlKey));
- DCHECK(native_control);
- WNDPROC original_handler = native_control->container_->original_handler_;
- DCHECK(original_handler);
-
- if (message == WM_KEYDOWN &&
- native_control->OnKeyDown(ui::KeyboardCodeForWindowsKeyCode(w_param))) {
- return 0;
- } else if (message == WM_SETFOCUS) {
- // Let the focus manager know that the focus changed.
- FocusManager* focus_manager = native_control->GetFocusManager();
- if (focus_manager) {
- focus_manager->SetFocusedView(native_control);
- } else {
- NOTREACHED();
- }
- } else if (message == WM_DESTROY) {
- gfx::SetWindowProc(window, reinterpret_cast<WNDPROC>(original_handler));
- native_control->container_->prop_.reset();
- }
-
- return CallWindowProc(reinterpret_cast<WNDPROC>(original_handler), window,
- message, w_param, l_param);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/native_control.h b/chromium/ui/views/controls/native_control.h
deleted file mode 100644
index 80aa5887cf1..00000000000
--- a/chromium/ui/views/controls/native_control.h
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
-#define UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
-
-#include <windows.h>
-
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/views/view.h"
-
-namespace views {
-
-class NativeViewHost;
-class NativeControlContainer;
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// NativeControl is an abstract view that is used to implement views wrapping
-// native controls. Subclasses can simply implement CreateNativeControl() to
-// wrap a new kind of control
-//
-////////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT NativeControl : public View {
- public:
- enum Alignment {
- LEADING = 0,
- CENTER,
- TRAILING };
-
- NativeControl();
- virtual ~NativeControl();
-
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE;
- virtual void Layout();
-
- // Overridden to properly set the native control state.
- virtual void SetVisible(bool f);
- virtual void OnEnabledChanged();
-
- // Overridden to do nothing.
- virtual void OnPaint(gfx::Canvas* canvas);
-
- protected:
- friend class NativeControlContainer;
-
- // Overridden by sub-classes to create the windows control which is wrapped
- virtual HWND CreateNativeControl(HWND parent_container) = 0;
-
- // Invoked when the native control sends a WM_NOTIFY message to its parent
- virtual LRESULT OnNotify(int w_param, LPNMHDR l_param) = 0;
-
- // Invoked when the native control sends a WM_COMMAND message to its parent
- virtual LRESULT OnCommand(UINT code, int id, HWND source) { return 0; }
-
- // Invoked when the appropriate gesture for a context menu is issued.
- virtual void OnContextMenu(const POINT& location);
-
- // Overridden so to set the native focus to the native control.
- virtual void OnFocus();
-
- // Invoked when the native control sends a WM_DESTORY message to its parent.
- virtual void OnDestroy() { }
-
- // Return the native control
- virtual HWND GetNativeControlHWND();
-
- // Invoked by the native windows control when it has been destroyed. This is
- // invoked AFTER WM_DESTORY has been sent. Any window commands send to the
- // HWND will most likely fail.
- void NativeControlDestroyed();
-
- // Overridden so that the control properly reflects parent's visibility.
- virtual void VisibilityChanged(View* starting_from, bool is_visible);
-
- // Controls that have fixed sizes should call these methods to specify the
- // actual size and how they should be aligned within their parent.
- void SetFixedWidth(int width, Alignment alignment);
- void SetFixedHeight(int height, Alignment alignment);
-
- // Invoked when a key is pressed on the control.
- // Should return true if the key message was processed, false otherwise.
- virtual bool OnKeyDown(ui::KeyboardCode virtual_key_code) { return false; }
-
- // Returns additional extended style flags. When subclasses call
- // CreateWindowEx in order to create the underlying control, they must OR the
- // ExStyle parameter with the value returned by this function.
- //
- // We currently use this method in order to add flags such as WS_EX_LAYOUTRTL
- // to the HWND for views with right-to-left UI layout.
- DWORD GetAdditionalExStyle() const;
-
- // TODO(xji): we use the following temporary function as we transition the
- // various native controls to use the right set of RTL flags. This function
- // will go away (and be replaced by GetAdditionalExStyle()) once all the
- // controls are properly transitioned.
- DWORD GetAdditionalRTLStyle() const;
-
- // This variable is protected to provide subclassers direct access. However
- // subclassers should always check for NULL since this variable is only
- // initialized in ValidateNativeControl().
- NativeViewHost* hwnd_view_;
-
- // Fixed size information. -1 for a size means no fixed size.
- int fixed_width_;
- Alignment horizontal_alignment_;
- int fixed_height_;
- Alignment vertical_alignment_;
-
- private:
-
- void ValidateNativeControl();
-
- static LRESULT CALLBACK NativeControlWndProc(HWND window, UINT message,
- WPARAM w_param, LPARAM l_param);
-
- NativeControlContainer* container_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeControl);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
diff --git a/chromium/ui/views/controls/native_control_win.cc b/chromium/ui/views/controls/native_control_win.cc
deleted file mode 100644
index c50411d13f5..00000000000
--- a/chromium/ui/views/controls/native_control_win.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/native_control_win.h"
-
-#include <windowsx.h>
-
-#include "base/logging.h"
-#include "ui/base/accessibility/accessibility_types.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/base/view_prop.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/views/controls/combobox/combobox.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/widget/widget.h"
-
-using ui::ViewProp;
-
-const char kNativeControlWinKey[] = "__NATIVE_CONTROL_WIN__";
-
-namespace views {
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeControlWin, public:
-
-NativeControlWin::NativeControlWin() : original_wndproc_(NULL) {
-}
-
-NativeControlWin::~NativeControlWin() {
- HWND hwnd = native_view();
- if (hwnd) {
- // Destroy the hwnd if it still exists. Otherwise we won't have shut things
- // down correctly, leading to leaking and crashing if another message
- // comes in for the hwnd.
- Detach();
- DestroyWindow(hwnd);
- }
-}
-
-bool NativeControlWin::ProcessMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) {
- switch (message) {
- case WM_CONTEXTMENU:
- ShowContextMenu(gfx::Point(GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)));
- *result = 0;
- return true;
- case WM_CTLCOLORBTN:
- case WM_CTLCOLORSTATIC:
- *result = GetControlColor(message, reinterpret_cast<HDC>(w_param),
- native_view());
- return true;
- }
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeControlWin, View overrides:
-
-void NativeControlWin::OnEnabledChanged() {
- View::OnEnabledChanged();
- if (native_view())
- EnableWindow(native_view(), enabled());
-}
-
-void NativeControlWin::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- // Call the base class to hide the view if we're being removed.
- NativeViewHost::ViewHierarchyChanged(details);
-
- // Create the HWND when we're added to a valid Widget. Many controls need a
- // parent HWND to function properly.
- if (details.is_add && GetWidget() && !native_view())
- CreateNativeControl();
-}
-
-void NativeControlWin::VisibilityChanged(View* starting_from, bool is_visible) {
- // We might get called due to visibility changes at any point in the
- // hierarchy, lets check whether we are really visible or not.
- bool is_drawn = IsDrawn();
- if (!is_drawn && native_view()) {
- // We destroy the child control HWND when we become invisible because of the
- // performance cost of maintaining many HWNDs.
- HWND hwnd = native_view();
- Detach();
- DestroyWindow(hwnd);
- } else if (is_drawn && !native_view()) {
- if (GetWidget())
- CreateNativeControl();
- }
- if (is_drawn) {
- // The view becomes visible after native control is created.
- // Layout now.
- Layout();
- }
-}
-
-void NativeControlWin::OnFocus() {
- DCHECK(native_view());
- SetFocus(native_view());
-
- // Since we are being wrapped by a view, accessibility should receive
- // the super class as the focused view.
- View* parent_view = parent();
-
- // Due to some controls not behaving as expected without having
- // a native win32 control, we don't always send a native (MSAA)
- // focus notification.
- bool send_native_event =
- strcmp(parent_view->GetClassName(), Combobox::kViewClassName) &&
- parent_view->HasFocus();
-
- // Send the accessibility focus notification.
- parent_view->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_FOCUS, send_native_event);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeControlWin, protected:
-
-void NativeControlWin::ShowContextMenu(const gfx::Point& location) {
- if (!context_menu_controller())
- return;
-
- if (location.x() == -1 && location.y() == -1) {
- View::ShowContextMenu(GetKeyboardContextMenuLocation(),
- ui::MENU_SOURCE_KEYBOARD);
- } else {
- View::ShowContextMenu(location, ui::MENU_SOURCE_MOUSE);
- }
-}
-
-void NativeControlWin::NativeControlCreated(HWND native_control) {
- // Associate this object with the control's HWND so that NativeWidgetWin can
- // find this object when it receives messages from it.
- props_.push_back(new ViewProp(native_control, kNativeControlWinKey, this));
- props_.push_back(ChildWindowMessageProcessor::Register(native_control, this));
-
- // Subclass so we get WM_KEYDOWN and WM_SETFOCUS messages.
- original_wndproc_ = gfx::SetWindowProc(
- native_control, &NativeControlWin::NativeControlWndProc);
-
- Attach(native_control);
- // native_view() is now valid.
-
- // Update the newly created HWND with any resident enabled state.
- EnableWindow(native_view(), enabled());
-
- // This message ensures that the focus border is shown.
- SendMessage(native_view(), WM_CHANGEUISTATE,
- MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
-}
-
-DWORD NativeControlWin::GetAdditionalExStyle() const {
- // If the UI for the view is mirrored, we should make sure we add the
- // extended window style for a right-to-left layout so the subclass creates
- // a mirrored HWND for the underlying control.
- DWORD ex_style = 0;
- if (base::i18n::IsRTL())
- ex_style |= l10n_util::GetExtendedStyles();
-
- return ex_style;
-}
-
-DWORD NativeControlWin::GetAdditionalRTLStyle() const {
- // If the UI for the view is mirrored, we should make sure we add the
- // extended window style for a right-to-left layout so the subclass creates
- // a mirrored HWND for the underlying control.
- DWORD ex_style = 0;
- if (base::i18n::IsRTL())
- ex_style |= l10n_util::GetExtendedTooltipStyles();
-
- return ex_style;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeControlWin, private:
-
-LRESULT NativeControlWin::GetControlColor(UINT message, HDC dc, HWND sender) {
- View *ancestor = this;
- while (ancestor) {
- const Background* background = ancestor->background();
- if (background) {
- HBRUSH brush = background->GetNativeControlBrush();
- if (brush)
- return reinterpret_cast<LRESULT>(brush);
- }
- ancestor = ancestor->parent();
- }
-
- // COLOR_BTNFACE is the default for dialog box backgrounds.
- return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE));
-}
-
-// static
-LRESULT NativeControlWin::NativeControlWndProc(HWND window,
- UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- NativeControlWin* native_control = reinterpret_cast<NativeControlWin*>(
- ViewProp::GetValue(window, kNativeControlWinKey));
- DCHECK(native_control);
-
- if (message == WM_KEYDOWN &&
- native_control->OnKeyDown(static_cast<int>(w_param))) {
- return 0;
- } else if (message == WM_SETFOCUS) {
- // Let the focus manager know that the focus changed.
- FocusManager* focus_manager = native_control->GetFocusManager();
- if (focus_manager) {
- focus_manager->SetFocusedView(native_control->focus_view());
- } else {
- NOTREACHED();
- }
- } else if (message == WM_DESTROY) {
- native_control->props_.clear();
- gfx::SetWindowProc(window, native_control->original_wndproc_);
- }
-
- return CallWindowProc(native_control->original_wndproc_, window, message,
- w_param, l_param);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/native_control_win.h b/chromium/ui/views/controls/native_control_win.h
deleted file mode 100644
index 3ee5681f1dc..00000000000
--- a/chromium/ui/views/controls/native_control_win.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
-#define UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_vector.h"
-#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/widget/child_window_message_processor.h"
-
-namespace ui {
-class ViewProp;
-}
-
-namespace views {
-
-// A View that hosts a native Windows control.
-class NativeControlWin : public ChildWindowMessageProcessor,
- public NativeViewHost {
- public:
- NativeControlWin();
- virtual ~NativeControlWin();
-
- // Called by our subclassed window procedure when a WM_KEYDOWN message is
- // received by the HWND created by an object derived from NativeControlWin.
- // Returns true if the key was processed, false otherwise.
- virtual bool OnKeyDown(int vkey) { return false; }
-
- // Overridden from ChildWindowMessageProcessor:
- virtual bool ProcessMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) OVERRIDE;
-
- // Overridden from View:
- virtual void OnEnabledChanged() OVERRIDE;
-
- protected:
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE;
- virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
- virtual void OnFocus() OVERRIDE;
-
- // Called by the containing NativeWidgetWin when a WM_CONTEXTMENU message is
- // received from the HWND created by an object derived from NativeControlWin.
- virtual void ShowContextMenu(const gfx::Point& location);
-
- // Called when the NativeControlWin is attached to a View hierarchy with a
- // valid Widget. The NativeControlWin should use this opportunity to create
- // its associated HWND.
- virtual void CreateNativeControl() = 0;
-
- // MUST be called by the subclass implementation of |CreateNativeControl|
- // immediately after creating the control HWND, otherwise it won't be attached
- // to the NativeViewHost and will be effectively orphaned.
- virtual void NativeControlCreated(HWND native_control);
-
- // Returns additional extended style flags. When subclasses call
- // CreateWindowEx in order to create the underlying control, they must OR the
- // ExStyle parameter with the value returned by this function.
- //
- // We currently use this method in order to add flags such as WS_EX_LAYOUTRTL
- // to the HWND for views with right-to-left UI layout.
- DWORD GetAdditionalExStyle() const;
-
- // TODO(xji): we use the following temporary function as we transition the
- // various native controls to use the right set of RTL flags. This function
- // will go away (and be replaced by GetAdditionalExStyle()) once all the
- // controls are properly transitioned.
- DWORD GetAdditionalRTLStyle() const;
-
- private:
- typedef ScopedVector<ui::ViewProp> ViewProps;
-
- // Called by the containing NativeWidgetWin when a message of type
- // WM_CTLCOLORBTN or WM_CTLCOLORSTATIC is sent from the HWND created by an
- // object derived from NativeControlWin.
- LRESULT GetControlColor(UINT message, HDC dc, HWND sender);
-
- // Our subclass window procedure for the attached control.
- static LRESULT CALLBACK NativeControlWndProc(HWND window,
- UINT message,
- WPARAM w_param,
- LPARAM l_param);
-
- // The window procedure before we subclassed.
- WNDPROC original_wndproc_;
-
- ViewProps props_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeControlWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
diff --git a/chromium/ui/views/controls/prefix_delegate.h b/chromium/ui/views/controls/prefix_delegate.h
index 41d30d43cc8..07d85989f0e 100644
--- a/chromium/ui/views/controls/prefix_delegate.h
+++ b/chromium/ui/views/controls/prefix_delegate.h
@@ -23,7 +23,7 @@ class VIEWS_EXPORT PrefixDelegate : public View {
virtual void SetSelectedRow(int row) = 0;
// Returns the item at the specified row.
- virtual string16 GetTextForRow(int row) = 0;
+ virtual base::string16 GetTextForRow(int row) = 0;
protected:
virtual ~PrefixDelegate() {}
diff --git a/chromium/ui/views/controls/prefix_selector.cc b/chromium/ui/views/controls/prefix_selector.cc
index d66a0346c84..c901edd2c11 100644
--- a/chromium/ui/views/controls/prefix_selector.cc
+++ b/chromium/ui/views/controls/prefix_selector.cc
@@ -47,12 +47,12 @@ void PrefixSelector::ConfirmCompositionText() {
void PrefixSelector::ClearCompositionText() {
}
-void PrefixSelector::InsertText(const string16& text) {
+void PrefixSelector::InsertText(const base::string16& text) {
OnTextInput(text);
}
-void PrefixSelector::InsertChar(char16 ch, int flags) {
- OnTextInput(string16(1, ch));
+void PrefixSelector::InsertChar(base::char16 ch, int flags) {
+ OnTextInput(base::string16(1, ch));
}
gfx::NativeWindow PrefixSelector::GetAttachedWindow() const {
@@ -115,7 +115,7 @@ bool PrefixSelector::DeleteRange(const gfx::Range& range) {
}
bool PrefixSelector::GetTextFromRange(const gfx::Range& range,
- string16* text) const {
+ base::string16* text) const {
return false;
}
@@ -143,7 +143,14 @@ void PrefixSelector::OnCandidateWindowUpdated() {
void PrefixSelector::OnCandidateWindowHidden() {
}
-void PrefixSelector::OnTextInput(const string16& text) {
+bool PrefixSelector::IsEditingCommandEnabled(int command_id) {
+ return false;
+}
+
+void PrefixSelector::ExecuteEditingCommand(int command_id) {
+}
+
+void PrefixSelector::OnTextInput(const base::string16& text) {
// Small hack to filter out 'tab' and 'enter' input, as the expectation is
// that they are control characters and will not affect the currently-active
// prefix.
@@ -171,9 +178,9 @@ void PrefixSelector::OnTextInput(const string16& text) {
time_of_last_key_ = now;
const int start_row = row;
- const string16 lower_text(base::i18n::ToLower(current_text_));
+ const base::string16 lower_text(base::i18n::ToLower(current_text_));
do {
- if (TextAtRowMatchesText(row, current_text_)) {
+ if (TextAtRowMatchesText(row, lower_text)) {
prefix_delegate_->SetSelectedRow(row);
return;
}
@@ -182,8 +189,8 @@ void PrefixSelector::OnTextInput(const string16& text) {
}
bool PrefixSelector::TextAtRowMatchesText(int row,
- const string16& lower_text) {
- const string16 model_text(
+ const base::string16& lower_text) {
+ const base::string16 model_text(
base::i18n::ToLower(prefix_delegate_->GetTextForRow(row)));
return (model_text.size() >= lower_text.size()) &&
(model_text.compare(0, lower_text.size(), lower_text) == 0);
diff --git a/chromium/ui/views/controls/prefix_selector.h b/chromium/ui/views/controls/prefix_selector.h
index 57f6dcfe183..255046f60df 100644
--- a/chromium/ui/views/controls/prefix_selector.h
+++ b/chromium/ui/views/controls/prefix_selector.h
@@ -29,8 +29,8 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
const ui::CompositionText& composition) OVERRIDE;
virtual void ConfirmCompositionText() OVERRIDE;
virtual void ClearCompositionText() OVERRIDE;
- virtual void InsertText(const string16& text) OVERRIDE;
- virtual void InsertChar(char16 ch, int flags) OVERRIDE;
+ virtual void InsertText(const base::string16& text) OVERRIDE;
+ virtual void InsertChar(base::char16 ch, int flags) OVERRIDE;
virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
virtual ui::TextInputType GetTextInputType() const OVERRIDE;
virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
@@ -45,7 +45,7 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
virtual bool GetTextFromRange(const gfx::Range& range,
- string16* text) const OVERRIDE;
+ base::string16* text) const OVERRIDE;
virtual void OnInputMethodChanged() OVERRIDE;
virtual bool ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) OVERRIDE;
@@ -55,12 +55,15 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
virtual void OnCandidateWindowUpdated() OVERRIDE;
virtual void OnCandidateWindowHidden() OVERRIDE;
+ virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE;
+ virtual void ExecuteEditingCommand(int command_id) OVERRIDE;
+
private:
// Invoked when text is typed. Tries to change the selection appropriately.
- void OnTextInput(const string16& text);
+ void OnTextInput(const base::string16& text);
// Returns true if the text of the node at |row| starts with |lower_text|.
- bool TextAtRowMatchesText(int row, const string16& lower_text);
+ bool TextAtRowMatchesText(int row, const base::string16& lower_text);
// Clears |current_text_| and resets |time_of_last_key_|.
void ClearText();
@@ -70,7 +73,7 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
// Time OnTextInput() was last invoked.
base::TimeTicks time_of_last_key_;
- string16 current_text_;
+ base::string16 current_text_;
DISALLOW_COPY_AND_ASSIGN(PrefixSelector);
};
diff --git a/chromium/ui/views/controls/prefix_selector_unittest.cc b/chromium/ui/views/controls/prefix_selector_unittest.cc
index c39e6cc652a..031c0079aee 100644
--- a/chromium/ui/views/controls/prefix_selector_unittest.cc
+++ b/chromium/ui/views/controls/prefix_selector_unittest.cc
@@ -11,6 +11,8 @@
#include "ui/views/controls/prefix_delegate.h"
#include "ui/views/test/views_test_base.h"
+using base::ASCIIToUTF16;
+
namespace views {
class TestPrefixDelegate : public PrefixDelegate {
@@ -36,12 +38,12 @@ class TestPrefixDelegate : public PrefixDelegate {
selected_row_ = row;
}
- virtual string16 GetTextForRow(int row) OVERRIDE {
+ virtual base::string16 GetTextForRow(int row) OVERRIDE {
return rows_[row];
}
private:
- std::vector<string16> rows_;
+ std::vector<base::string16> rows_;
int selected_row_;
DISALLOW_COPY_AND_ASSIGN(TestPrefixDelegate);
diff --git a/chromium/ui/views/controls/progress_bar.cc b/chromium/ui/views/controls/progress_bar.cc
index 087c2df9830..0d6ed17f5e0 100644
--- a/chromium/ui/views/controls/progress_bar.cc
+++ b/chromium/ui/views/controls/progress_bar.cc
@@ -11,7 +11,7 @@
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkXfermode.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
namespace {
@@ -81,7 +81,7 @@ void FillRoundRect(gfx::Canvas* canvas,
p[1].iset(x, y + h);
}
skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear(
- p, colors, points, count, SkShader::kClamp_TileMode, NULL));
+ p, colors, points, count, SkShader::kClamp_TileMode));
paint.setShader(s.get());
canvas->DrawPath(path, paint);
@@ -167,22 +167,23 @@ void ProgressBar::SetValue(double value) {
}
}
-void ProgressBar::SetTooltipText(const string16& tooltip_text) {
+void ProgressBar::SetTooltipText(const base::string16& tooltip_text) {
tooltip_text_ = tooltip_text;
}
-bool ProgressBar::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool ProgressBar::GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const {
DCHECK(tooltip);
*tooltip = tooltip_text_;
return !tooltip_text_.empty();
}
-void ProgressBar::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PROGRESSBAR;
- state->state = ui::AccessibilityTypes::STATE_READONLY;
+void ProgressBar::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_PROGRESS_INDICATOR;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
}
-gfx::Size ProgressBar::GetPreferredSize() {
+gfx::Size ProgressBar::GetPreferredSize() const {
gfx::Size pref_size(100, 11);
gfx::Insets insets = GetInsets();
pref_size.Enlarge(insets.width(), insets.height());
@@ -227,7 +228,7 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
kCornerRadius,
0,
&inner_path);
- canvas->ClipPath(inner_path);
+ canvas->ClipPath(inner_path, false);
const SkColor bar_colors[] = {
kBarTopColor,
@@ -299,7 +300,7 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
skia::RefPtr<SkShader> s =
skia::AdoptRef(SkGradientShader::CreateLinear(
p, highlight_colors, highlight_points,
- arraysize(highlight_colors), SkShader::kClamp_TileMode, NULL));
+ arraysize(highlight_colors), SkShader::kClamp_TileMode));
paint.setShader(s.get());
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
canvas->DrawRect(gfx::Rect(highlight_left, 0,
diff --git a/chromium/ui/views/controls/progress_bar.h b/chromium/ui/views/controls/progress_bar.h
index 1f3d595534c..b6d3851baaf 100644
--- a/chromium/ui/views/controls/progress_bar.h
+++ b/chromium/ui/views/controls/progress_bar.h
@@ -35,18 +35,18 @@ class VIEWS_EXPORT ProgressBar : public View {
// Sets the tooltip text. Default behavior for a progress bar is to show no
// tooltip on mouse hover. Calling this lets you set a custom tooltip. To
// revert to default behavior, call this with an empty string.
- void SetTooltipText(const string16& tooltip_text);
+ void SetTooltipText(const base::string16& tooltip_text);
// Overridden from View:
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
private:
static const char kViewClassName[];
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
@@ -58,7 +58,7 @@ class VIEWS_EXPORT ProgressBar : public View {
double current_value_;
// Tooltip text.
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
DISALLOW_COPY_AND_ASSIGN(ProgressBar);
};
diff --git a/chromium/ui/views/controls/progress_bar_unittest.cc b/chromium/ui/views/controls/progress_bar_unittest.cc
index 78df2e17d0d..b9067b20c9b 100644
--- a/chromium/ui/views/controls/progress_bar_unittest.cc
+++ b/chromium/ui/views/controls/progress_bar_unittest.cc
@@ -6,16 +6,16 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
namespace views {
TEST(ProgressBarTest, TooltipTextProperty) {
ProgressBar bar;
- string16 tooltip = ASCIIToUTF16("Some text");
+ base::string16 tooltip = base::ASCIIToUTF16("Some text");
EXPECT_FALSE(bar.GetTooltipText(gfx::Point(), &tooltip));
- EXPECT_EQ(string16(), tooltip);
- string16 tooltip_text = ASCIIToUTF16("My progress");
+ EXPECT_EQ(base::string16(), tooltip);
+ base::string16 tooltip_text = base::ASCIIToUTF16("My progress");
bar.SetTooltipText(tooltip_text);
EXPECT_TRUE(bar.GetTooltipText(gfx::Point(), &tooltip));
EXPECT_EQ(tooltip_text, tooltip);
@@ -25,11 +25,11 @@ TEST(ProgressBarTest, Accessibility) {
ProgressBar bar;
bar.SetValue(62);
- ui::AccessibleViewState state;
+ ui::AXViewState state;
bar.GetAccessibleState(&state);
- EXPECT_EQ(ui::AccessibilityTypes::ROLE_PROGRESSBAR, state.role);
- EXPECT_EQ(string16(), state.name);
- EXPECT_TRUE(ui::AccessibilityTypes::STATE_READONLY & state.state);
+ EXPECT_EQ(ui::AX_ROLE_PROGRESS_INDICATOR, state.role);
+ EXPECT_EQ(base::string16(), state.name);
+ EXPECT_TRUE(state.HasStateFlag(ui::AX_STATE_READ_ONLY));
}
} // namespace views
diff --git a/chromium/ui/views/controls/resize_area.cc b/chromium/ui/views/controls/resize_area.cc
index 845f2e8d42d..8a5159f7eda 100644
--- a/chromium/ui/views/controls/resize_area.cc
+++ b/chromium/ui/views/controls/resize_area.cc
@@ -5,13 +5,11 @@
#include "ui/views/controls/resize_area.h"
#include "base/logging.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/resize_area_delegate.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+#include "ui/views/native_cursor.h"
namespace views {
@@ -33,14 +31,8 @@ const char* ResizeArea::GetClassName() const {
}
gfx::NativeCursor ResizeArea::GetCursor(const ui::MouseEvent& event) {
- if (!enabled())
- return gfx::kNullCursor;
-#if defined(USE_AURA)
- return ui::kCursorEastWestResize;
-#elif defined(OS_WIN)
- static HCURSOR g_resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
- return g_resize_cursor;
-#endif
+ return enabled() ? GetNativeEastWestResizeCursor()
+ : gfx::kNullCursor;
}
bool ResizeArea::OnMousePressed(const ui::MouseEvent& event) {
@@ -73,8 +65,8 @@ void ResizeArea::OnMouseCaptureLost() {
ReportResizeAmount(initial_position_, true);
}
-void ResizeArea::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_SEPARATOR;
+void ResizeArea::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SPLITTER;
}
void ResizeArea::ReportResizeAmount(int resize_amount, bool last_update) {
diff --git a/chromium/ui/views/controls/resize_area.h b/chromium/ui/views/controls/resize_area.h
index 288b912ba80..12ec310026e 100644
--- a/chromium/ui/views/controls/resize_area.h
+++ b/chromium/ui/views/controls/resize_area.h
@@ -32,7 +32,7 @@ class VIEWS_EXPORT ResizeArea : public View {
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseCaptureLost() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
private:
// Report the amount the user resized by to the delegate, accounting for
diff --git a/chromium/ui/views/controls/scroll_view.cc b/chromium/ui/views/controls/scroll_view.cc
index d835c1ebdf8..51db071b71f 100644
--- a/chromium/ui/views/controls/scroll_view.cc
+++ b/chromium/ui/views/controls/scroll_view.cc
@@ -20,22 +20,16 @@ namespace {
// Subclass of ScrollView that resets the border when the theme changes.
class ScrollViewWithBorder : public views::ScrollView {
public:
- ScrollViewWithBorder() {
- SetThemeSpecificState();
- }
+ ScrollViewWithBorder() {}
// View overrides;
virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE {
- SetThemeSpecificState();
+ SetBorder(Border::CreateSolidBorder(
+ 1,
+ theme->GetSystemColor(ui::NativeTheme::kColorId_UnfocusedBorderColor)));
}
private:
- void SetThemeSpecificState() {
- set_border(Border::CreateSolidBorder(
- 1, GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_UnfocusedBorderColor)));
- }
-
DISALLOW_COPY_AND_ASSIGN(ScrollViewWithBorder);
};
@@ -116,6 +110,8 @@ ScrollView::ScrollView()
horiz_sb_(new NativeScrollBar(true)),
vert_sb_(new NativeScrollBar(false)),
resize_corner_(NULL),
+ min_height_(-1),
+ max_height_(-1),
hide_horizontal_scrollbar_(false) {
set_notify_enter_exit_on_child(true);
@@ -162,6 +158,11 @@ gfx::Rect ScrollView::GetVisibleRect() const {
contents_viewport_->width(), contents_viewport_->height());
}
+void ScrollView::ClipHeightTo(int min_height, int max_height) {
+ min_height_ = min_height;
+ max_height_ = max_height;
+}
+
int ScrollView::GetScrollBarWidth() const {
return vert_sb_ ? vert_sb_->GetLayoutSize() : 0;
}
@@ -186,7 +187,40 @@ void ScrollView::SetVerticalScrollBar(ScrollBar* vert_sb) {
vert_sb_ = vert_sb;
}
+gfx::Size ScrollView::GetPreferredSize() const {
+ if (!is_bounded())
+ return View::GetPreferredSize();
+
+ gfx::Size size = contents()->GetPreferredSize();
+ size.SetToMax(gfx::Size(size.width(), min_height_));
+ size.SetToMin(gfx::Size(size.width(), max_height_));
+ gfx::Insets insets = GetInsets();
+ size.Enlarge(insets.width(), insets.height());
+ return size;
+}
+
+int ScrollView::GetHeightForWidth(int width) const {
+ if (!is_bounded())
+ return View::GetHeightForWidth(width);
+
+ gfx::Insets insets = GetInsets();
+ width = std::max(0, width - insets.width());
+ int height = contents()->GetHeightForWidth(width) + insets.height();
+ return std::min(std::max(height, min_height_), max_height_);
+}
+
void ScrollView::Layout() {
+ if (is_bounded()) {
+ int content_width = width();
+ int content_height = contents()->GetHeightForWidth(content_width);
+ if (content_height > height()) {
+ content_width = std::max(content_width - GetScrollBarWidth(), 0);
+ content_height = contents()->GetHeightForWidth(content_width);
+ }
+ if (contents()->bounds().size() != gfx::Size(content_width, content_height))
+ contents()->SetBounds(0, 0, content_width, content_height);
+ }
+
// Most views will want to auto-fit the available space. Most of them want to
// use all available width (without overflowing) and only overflow in
// height. Examples are HistoryView, MostVisitedView, DownloadTabView, etc.
diff --git a/chromium/ui/views/controls/scroll_view.h b/chromium/ui/views/controls/scroll_view.h
index da87ffdc753..c1c18713af0 100644
--- a/chromium/ui/views/controls/scroll_view.h
+++ b/chromium/ui/views/controls/scroll_view.h
@@ -31,6 +31,7 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
static const char kViewClassName[];
ScrollView();
+
virtual ~ScrollView();
// Creates a ScrollView with a theme specific border.
@@ -52,6 +53,13 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
hide_horizontal_scrollbar_ = visible;
}
+ // Turns this scroll view into a bounded scroll view, with a fixed height.
+ // By default, a ScrollView will stretch to fill its outer container.
+ void ClipHeightTo(int min_height, int max_height);
+
+ // Returns whether or not the ScrollView is bounded (as set by ClipHeightTo).
+ bool is_bounded() const { return max_height_ >= 0 && min_height_ >= 0; }
+
// Retrieves the width/height of scrollbars. These return 0 if the scrollbar
// has not yet been created.
int GetScrollBarWidth() const;
@@ -67,6 +75,8 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
void SetVerticalScrollBar(ScrollBar* vert_sb);
// View overrides:
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnMouseWheel(const ui::MouseWheelEvent& e) OVERRIDE;
@@ -127,6 +137,11 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
// Resize corner.
View* resize_corner_;
+ // The min and max height for the bounded scroll view. These are negative
+ // values if the view is not bounded.
+ int min_height_;
+ int max_height_;
+
// If true, never show the horizontal scrollbar (even if the contents is wider
// than the viewport).
bool hide_horizontal_scrollbar_;
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index f0bdbd5443d..8f34377553f 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -5,11 +5,17 @@
#include "ui/views/controls/scroll_view.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
+#include "ui/views/test/test_views.h"
namespace views {
namespace {
+const int kWidth = 100;
+const int kMinHeight = 50;
+const int kMaxHeight = 100;
+
// View implementation that allows setting the preferred size.
class CustomView : public View {
public:
@@ -20,7 +26,7 @@ class CustomView : public View {
PreferredSizeChanged();
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return preferred_size_;
}
@@ -148,7 +154,6 @@ TEST(ScrollViewTest, ScrollBarsWithHeader) {
ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL);
EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible());
-
// Size the contents such that horizontal scrollbar is needed.
contents->SetBounds(0, 0, 400, 50);
scroll_view.Layout();
@@ -214,7 +219,6 @@ TEST(ScrollViewTest, HeaderScrollsWithContent) {
EXPECT_EQ("-1,0", header->bounds().origin().ToString());
}
-
// Verifies ScrollRectToVisible() on the child works.
TEST(ScrollViewTest, ScrollRectToVisible) {
ScrollView scroll_view;
@@ -237,4 +241,97 @@ TEST(ScrollViewTest, ScrollRectToVisible) {
EXPECT_EQ(-(415 - viewport_height), contents->y());
}
+// Verifies ClipHeightTo() uses the height of the content when it is between the
+// minimum and maximum height values.
+TEST(ScrollViewTest, ClipHeightToNormalContentHeight) {
+ ScrollView scroll_view;
+
+ scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
+
+ const int kNormalContentHeight = 75;
+ scroll_view.SetContents(
+ new views::StaticSizedView(gfx::Size(kWidth, kNormalContentHeight)));
+
+ EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight),
+ scroll_view.GetPreferredSize());
+
+ scroll_view.SizeToPreferredSize();
+ scroll_view.Layout();
+
+ EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight),
+ scroll_view.contents()->size());
+ EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), scroll_view.size());
+}
+
+// Verifies ClipHeightTo() uses the minimum height when the content is shorter
+// thamn the minimum height value.
+TEST(ScrollViewTest, ClipHeightToShortContentHeight) {
+ ScrollView scroll_view;
+
+ scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
+
+ const int kShortContentHeight = 10;
+ scroll_view.SetContents(
+ new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight)));
+
+ EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.GetPreferredSize());
+
+ scroll_view.SizeToPreferredSize();
+ scroll_view.Layout();
+
+ EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight),
+ scroll_view.contents()->size());
+ EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.size());
+}
+
+// Verifies ClipHeightTo() uses the maximum height when the content is longer
+// thamn the maximum height value.
+TEST(ScrollViewTest, ClipHeightToTallContentHeight) {
+ ScrollView scroll_view;
+
+ // Use a scrollbar that is disabled by default, so the width of the content is
+ // not affected.
+ scroll_view.SetVerticalScrollBar(new views::OverlayScrollBar(false));
+
+ scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
+
+ const int kTallContentHeight = 1000;
+ scroll_view.SetContents(
+ new views::StaticSizedView(gfx::Size(kWidth, kTallContentHeight)));
+
+ EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view.GetPreferredSize());
+
+ scroll_view.SizeToPreferredSize();
+ scroll_view.Layout();
+
+ EXPECT_EQ(gfx::Size(kWidth, kTallContentHeight),
+ scroll_view.contents()->size());
+ EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view.size());
+}
+
+// Verifies that when ClipHeightTo() produces a scrollbar, it reduces the width
+// of the inner content of the ScrollView.
+TEST(ScrollViewTest, ClipHeightToScrollbarUsesWidth) {
+ ScrollView scroll_view;
+
+ scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
+
+ // Create a view that will be much taller than it is wide.
+ scroll_view.SetContents(new views::ProportionallySizedView(1000));
+
+ // Without any width, it will default to 0,0 but be overridden by min height.
+ scroll_view.SizeToPreferredSize();
+ EXPECT_EQ(gfx::Size(0, kMinHeight), scroll_view.GetPreferredSize());
+
+ gfx::Size new_size(kWidth, scroll_view.GetHeightForWidth(kWidth));
+ scroll_view.SetSize(new_size);
+ scroll_view.Layout();
+
+ int scroll_bar_width = scroll_view.GetScrollBarWidth();
+ int expected_width = kWidth - scroll_bar_width;
+ EXPECT_EQ(scroll_view.contents()->size().width(), expected_width);
+ EXPECT_EQ(scroll_view.contents()->size().height(), 1000 * expected_width);
+ EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view.size());
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
index 6271c2e1bfe..5e4d6a56fa3 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
@@ -17,6 +17,7 @@
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/scroll_view.h"
@@ -235,10 +236,19 @@ void BaseScrollBar::OnGestureEvent(ui::GestureEvent* event) {
}
if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
- if (ScrollByContentsOffset(IsHorizontal() ? event->details().scroll_x() :
- event->details().scroll_y())) {
- event->SetHandled();
+ float scroll_amount_f;
+ int scroll_amount;
+ if (IsHorizontal()) {
+ scroll_amount_f = event->details().scroll_x() - roundoff_error_.x();
+ scroll_amount = gfx::ToRoundedInt(scroll_amount_f);
+ roundoff_error_.set_x(scroll_amount - scroll_amount_f);
+ } else {
+ scroll_amount_f = event->details().scroll_y() - roundoff_error_.y();
+ scroll_amount = gfx::ToRoundedInt(scroll_amount_f);
+ roundoff_error_.set_y(scroll_amount - scroll_amount_f);
}
+ if (ScrollByContentsOffset(scroll_amount))
+ event->SetHandled();
return;
}
@@ -295,17 +305,22 @@ void BaseScrollBar::ShowContextMenuForView(View* source,
menu->AppendSeparator();
menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev);
menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext);
- if (menu_runner_->RunMenuAt(GetWidget(), NULL, gfx::Rect(p, gfx::Size()),
- views::MenuItemView::TOPLEFT, source_type, MenuRunner::HAS_MNEMONICS |
- views::MenuRunner::CONTEXT_MENU) ==
- MenuRunner::MENU_DELETED)
+ if (menu_runner_->RunMenuAt(
+ GetWidget(),
+ NULL,
+ gfx::Rect(p, gfx::Size()),
+ MENU_ANCHOR_TOPLEFT,
+ source_type,
+ MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
+ MenuRunner::MENU_DELETED) {
return;
+ }
}
///////////////////////////////////////////////////////////////////////////////
// BaseScrollBar, Menu::Delegate implementation:
-string16 BaseScrollBar::GetLabel(int id) const {
+base::string16 BaseScrollBar::GetLabel(int id) const {
int ids_value = 0;
switch (id) {
case ScrollBarContextMenuCommand_ScrollHere:
@@ -337,7 +352,7 @@ string16 BaseScrollBar::GetLabel(int id) const {
NOTREACHED() << "Invalid BaseScrollBar Context Menu command!";
}
- return ids_value ? l10n_util::GetStringUTF16(ids_value) : string16();
+ return ids_value ? l10n_util::GetStringUTF16(ids_value) : base::string16();
}
bool BaseScrollBar::IsCommandEnabled(int id) const {
@@ -378,7 +393,8 @@ void BaseScrollBar::ExecuteCommand(int id) {
///////////////////////////////////////////////////////////////////////////////
// BaseScrollBar, ScrollBar implementation:
-void BaseScrollBar::Update(int viewport_size, int content_size,
+void BaseScrollBar::Update(int viewport_size,
+ int content_size,
int contents_scroll_offset) {
ScrollBar::Update(viewport_size, content_size, contents_scroll_offset);
@@ -394,6 +410,7 @@ void BaseScrollBar::Update(int viewport_size, int content_size,
contents_scroll_offset = 0;
if (contents_scroll_offset > content_size)
contents_scroll_offset = content_size;
+ contents_scroll_offset_ = contents_scroll_offset;
// Thumb Height and Thumb Pos.
// The height of the thumb is the ratio of the Viewport height to the
@@ -488,7 +505,7 @@ int BaseScrollBar::CalculateThumbPosition(int contents_scroll_offset) const {
}
int BaseScrollBar::CalculateContentsOffset(int thumb_position,
- bool scroll_to_middle) const {
+ bool scroll_to_middle) const {
if (scroll_to_middle)
thumb_position = thumb_position - (thumb_->GetSize() / 2);
return (thumb_position * contents_size_) / GetTrackSize();
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
index a517b6c0645..068ad4ddb6f 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
@@ -64,7 +64,7 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
CustomButton::ButtonState new_state);
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE = 0;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE = 0;
virtual void Layout() OVERRIDE = 0;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
@@ -93,7 +93,7 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
ui::MenuSourceType source_type) OVERRIDE;
// Menu::Delegate overrides:
- virtual string16 GetLabel(int id) const OVERRIDE;
+ virtual base::string16 GetLabel(int id) const OVERRIDE;
virtual bool IsCommandEnabled(int id) const OVERRIDE;
virtual void ExecuteCommand(int id) OVERRIDE;
@@ -178,6 +178,12 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
scoped_ptr<MenuRunner> menu_runner_;
scoped_ptr<ScrollAnimator> scroll_animator_;
+ // Difference between current position and cumulative deltas obtained from
+ // scroll update events.
+ // TODO(tdresser): This should be removed when raw pixel scrolling for views
+ // is enabled. See crbug.com/329354.
+ gfx::Vector2dF roundoff_error_;
+
DISALLOW_COPY_AND_ASSIGN(BaseScrollBar);
};
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc
index 6eba692d626..0a765c42962 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc
@@ -35,15 +35,12 @@ void BaseScrollBarButton::OnMouseCaptureLost() {
void BaseScrollBarButton::RepeaterNotifyClick() {
// TODO(sky): See if we can convert to using |Screen| everywhere.
-#if defined(OS_WIN) && !defined(USE_AURA)
- gfx::Point cursor_point(GetMessagePos());
-#else
// TODO(scottmg): Native is wrong: http://crbug.com/133312
gfx::Point cursor_point =
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
-#endif
ui::MouseEvent event(ui::ET_MOUSE_RELEASED,
cursor_point, cursor_point,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
Button::NotifyClick(event);
}
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
index 0859fa903c1..c755441b8b4 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
@@ -44,7 +44,7 @@ class VIEWS_EXPORT BaseScrollBarThumb : public View {
int GetPosition() const;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE = 0;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE = 0;
protected:
// View overrides:
diff --git a/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.cc
deleted file mode 100644
index 2597cee0b78..00000000000
--- a/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/scrollbar/bitmap_scroll_bar.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "grit/ui_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/views/controls/menu/menu.h"
-#include "ui/views/controls/scroll_view.h"
-#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
-#include "ui/views/widget/widget.h"
-
-#if defined(OS_LINUX)
-#include "ui/views/screen.h"
-#endif
-
-#undef min
-#undef max
-
-namespace views {
-
-namespace {
-
-// The distance the mouse can be dragged outside the bounds of the thumb during
-// dragging before the scrollbar will snap back to its regular position.
-const int kScrollThumbDragOutSnap = 100;
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// AutorepeatButton
-//
-// A button that activates on mouse pressed rather than released, and that
-// continues to fire the clicked action as the mouse button remains pressed
-// down on the button.
-//
-///////////////////////////////////////////////////////////////////////////////
-class AutorepeatButton : public ImageButton {
- public:
- explicit AutorepeatButton(ButtonListener* listener)
- : ImageButton(listener),
- repeater_(base::Bind(&AutorepeatButton::NotifyClick,
- base::Unretained(this))) {
- }
- virtual ~AutorepeatButton() {}
-
- protected:
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
- Button::NotifyClick(event);
- repeater_.Start();
- return true;
- }
-
- virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
- OnMouseCaptureLost();
- }
-
- virtual void OnMouseCaptureLost() OVERRIDE {
- repeater_.Stop();
- }
-
- private:
- void NotifyClick() {
-#if defined(OS_WIN)
- gfx::Point cursor_point(GetMessagePos());
-#elif defined(OS_LINUX)
- gfx::Point cursor_point = gfx::Screen::GetCursorScreenPoint();
-#endif
- ui::MouseEvent event(ui::ET_MOUSE_RELEASED,
- cursor_point, cursor_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- Button::NotifyClick(event);
- }
-
- // The repeat controller that we use to repeatedly click the button when the
- // mouse button is down.
- RepeatController repeater_;
-
- DISALLOW_COPY_AND_ASSIGN(AutorepeatButton);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// BitmapScrollBarThumb
-//
-// A view that acts as the thumb in the scroll bar track that the user can
-// drag to scroll the associated contents view within the viewport.
-//
-///////////////////////////////////////////////////////////////////////////////
-class BitmapScrollBarThumb : public BaseScrollBarThumb {
- public:
- explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar)
- : BaseScrollBarThumb(scroll_bar),
- scroll_bar_(scroll_bar) {
- }
- virtual ~BitmapScrollBarThumb() { }
-
- // View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE {
- return gfx::Size(background_image()->width(),
- start_cap_image()->height() +
- end_cap_image()->height() +
- grippy_image()->height());
- }
-
- protected:
- // View overrides:
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
- canvas->DrawImageInt(*start_cap_image(), 0, 0);
- int top_cap_height = start_cap_image()->height();
- int bottom_cap_height = end_cap_image()->height();
- int thumb_body_height = height() - top_cap_height - bottom_cap_height;
- canvas->TileImageInt(*background_image(), 0, top_cap_height,
- background_image()->width(), thumb_body_height);
- canvas->DrawImageInt(*end_cap_image(), 0,
- height() - bottom_cap_height);
-
- // Paint the grippy over the track.
- int grippy_x = (width() - grippy_image()->width()) / 2;
- int grippy_y = (thumb_body_height - grippy_image()->height()) / 2;
- canvas->DrawImageInt(*grippy_image(), grippy_x, grippy_y);
- }
-
- private:
- // Returns the image rendered at the start of the thumb.
- gfx::ImageSkia* start_cap_image() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][GetState()];
- }
-
- // Returns the image rendered at the end of the thumb.
- gfx::ImageSkia* end_cap_image() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][GetState()];
- }
-
- // Returns the image that is tiled in the background of the thumb between
- // the start and the end caps.
- gfx::ImageSkia* background_image() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][GetState()];
- }
-
- // Returns the image that is rendered in the middle of the thumb
- // transparently over the background image.
- gfx::ImageSkia* grippy_image() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_GRIPPY]
- [CustomButton::STATE_NORMAL];
- }
-
- // The BitmapScrollBar that owns us.
- BitmapScrollBar* scroll_bar_;
-
- DISALLOW_COPY_AND_ASSIGN(BitmapScrollBarThumb);
-};
-
-} // namespace
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, public:
-
-BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons)
- : BaseScrollBar(horizontal, new BitmapScrollBarThumb(this)),
- prev_button_(new AutorepeatButton(this)),
- next_button_(new AutorepeatButton(this)),
- show_scroll_buttons_(show_scroll_buttons) {
- if (!show_scroll_buttons_) {
- prev_button_->SetVisible(false);
- next_button_->SetVisible(false);
- }
-
- AddChildView(prev_button_);
- AddChildView(next_button_);
-
- set_context_menu_controller(this);
- prev_button_->set_context_menu_controller(this);
- next_button_->set_context_menu_controller(this);
-}
-
-void BitmapScrollBar::SetImage(ScrollBarPart part,
- CustomButton::ButtonState state,
- gfx::ImageSkia* image_skia) {
- DCHECK(part < PART_COUNT);
- DCHECK(state < CustomButton::STATE_COUNT);
- switch (part) {
- case PREV_BUTTON:
- prev_button_->SetImage(state, image_skia);
- break;
- case NEXT_BUTTON:
- next_button_->SetImage(state, image_skia);
- break;
- case THUMB_START_CAP:
- case THUMB_MIDDLE:
- case THUMB_END_CAP:
- case THUMB_GRIPPY:
- case THUMB_TRACK:
- images_[part][state] = image_skia;
- break;
- }
-}
-
-int BitmapScrollBar::GetLayoutSize() const {
- gfx::Size prefsize = prev_button_->GetPreferredSize();
- return IsHorizontal() ? prefsize.height() : prefsize.width();
-}
-
-gfx::Rect BitmapScrollBar::GetTrackBounds() const {
- gfx::Size prefsize = prev_button_->GetPreferredSize();
- if (IsHorizontal()) {
- if (!show_scroll_buttons_)
- prefsize.set_width(0);
- int new_width =
- std::max(0, width() - (prefsize.width() * 2));
- gfx::Rect track_bounds(prefsize.width(), 0, new_width, prefsize.height());
- return track_bounds;
- }
- if (!show_scroll_buttons_)
- prefsize.set_height(0);
- gfx::Rect track_bounds(0, prefsize.height(), prefsize.width(),
- std::max(0, height() - (prefsize.height() * 2)));
- return track_bounds;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, View implementation:
-
-gfx::Size BitmapScrollBar::GetPreferredSize() {
- // In this case, we're returning the desired width of the scrollbar and its
- // minimum allowable height.
- gfx::Size button_prefsize = prev_button_->GetPreferredSize();
- return gfx::Size(button_prefsize.width(), button_prefsize.height() * 2);
-}
-
-void BitmapScrollBar::Layout() {
- // Size and place the two scroll buttons.
- if (show_scroll_buttons_) {
- gfx::Size prefsize = prev_button_->GetPreferredSize();
- prev_button_->SetBounds(0, 0, prefsize.width(), prefsize.height());
- prefsize = next_button_->GetPreferredSize();
- if (IsHorizontal()) {
- next_button_->SetBounds(width() - prefsize.width(), 0, prefsize.width(),
- prefsize.height());
- } else {
- next_button_->SetBounds(0, height() - prefsize.height(), prefsize.width(),
- prefsize.height());
- }
- } else {
- prev_button_->SetBounds(0, 0, 0, 0);
- next_button_->SetBounds(0, 0, 0, 0);
- }
-
- BaseScrollBarThumb* thumb = GetThumb();
- // Size and place the thumb
- gfx::Size thumb_prefsize = thumb->GetPreferredSize();
- gfx::Rect track_bounds = GetTrackBounds();
-
- // Preserve the height/width of the thumb (depending on orientation) as set
- // by the last call to |Update|, but coerce the width/height to be the
- // appropriate value for the images provided.
- if (IsHorizontal()) {
- thumb->SetBounds(thumb->x(), thumb->y(), thumb->width(),
- thumb_prefsize.height());
- } else {
- thumb->SetBounds(thumb->x(), thumb->y(), thumb_prefsize.width(),
- thumb->height());
- }
-
- // Hide the thumb if the track isn't tall enough to display even a tiny
- // thumb. The user can only use the mousewheel, scroll buttons or keyboard
- // in this scenario.
- if ((IsHorizontal() && (track_bounds.width() < thumb_prefsize.width()) ||
- (!IsHorizontal() && (track_bounds.height() < thumb_prefsize.height())))) {
- thumb->SetVisible(false);
- } else if (!thumb->visible()) {
- thumb->SetVisible(true);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, View implementation:
-
-void BitmapScrollBar::OnPaint(gfx::Canvas* canvas) {
- // Paint the track.
- gfx::Rect track_bounds = GetTrackBounds();
- canvas->TileImageInt(*images_[THUMB_TRACK][GetThumbTrackState()],
- track_bounds.x(), track_bounds.y(),
- track_bounds.width(), track_bounds.height());
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, ButtonListener implementation:
-
-void BitmapScrollBar::ButtonPressed(Button* sender, const ui::Event& event) {
- if (sender == prev_button_) {
- ScrollByAmount(SCROLL_PREV_LINE);
- } else if (sender == next_button_) {
- ScrollByAmount(SCROLL_NEXT_LINE);
- }
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.h b/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.h
deleted file mode 100644
index ac97af499cc..00000000000
--- a/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
-#define UI_VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
-
-#include "ui/views/controls/scrollbar/base_scroll_bar.h"
-
-namespace views {
-
-namespace {
-class BitmapScrollBarThumb;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// BitmapScrollBar
-//
-// A ScrollBar subclass that implements a scroll bar rendered using images
-// that the user provides. There are images for the up and down buttons, as
-// well as for the thumb and track. This is intended for creating UIs that
-// have customized, non-native appearances, like floating HUDs etc.
-//
-///////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT BitmapScrollBar : public BaseScrollBar,
- public ButtonListener {
- public:
- BitmapScrollBar(bool horizontal, bool show_scroll_buttons);
- virtual ~BitmapScrollBar() { }
-
- // A list of parts that the user may supply images for.
- enum ScrollBarPart {
- // The button used to represent scrolling up/left by 1 line.
- PREV_BUTTON = 0,
- // The button used to represent scrolling down/right by 1 line.
- // IMPORTANT: The code assumes the prev and next
- // buttons have equal width and equal height.
- NEXT_BUTTON,
- // The top/left segment of the thumb on the scrollbar.
- THUMB_START_CAP,
- // The tiled background image of the thumb.
- THUMB_MIDDLE,
- // The bottom/right segment of the thumb on the scrollbar.
- THUMB_END_CAP,
- // The grippy that is rendered in the center of the thumb.
- THUMB_GRIPPY,
- // The tiled background image of the thumb track.
- THUMB_TRACK,
- PART_COUNT
- };
-
- // Sets the image to be rendered for the specified part and state.
- void SetImage(ScrollBarPart part,
- CustomButton::ButtonState state,
- gfx::ImageSkia* image_skia);
-
-
- gfx::Rect GetTrackBounds() const;
-
- protected:
- // View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-
- // ScrollBar overrides:
- virtual int GetLayoutSize() const OVERRIDE;
-
- // BaseButton::ButtonListener overrides:
- virtual void ButtonPressed(Button* sender,
- const ui::Event& event) OVERRIDE;
-
- private:
- // Up/Down/Left/Right buttons.
- ImageButton* prev_button_;
- ImageButton* next_button_;
-
- // The thumb needs to be able to access the part images.
- friend BitmapScrollBarThumb;
- gfx::ImageSkia* images_[PART_COUNT][CustomButton::STATE_COUNT];
-
- // True if the scroll buttons at each end of the scroll bar should be shown.
- bool show_scroll_buttons_;
-
- DISALLOW_COPY_AND_ASSIGN(BitmapScrollBar);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
diff --git a/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc
index f263068ecd7..b3d1e6a3c32 100644
--- a/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc
@@ -28,7 +28,7 @@ class KennedyScrollBarThumb : public BaseScrollBarThumb {
protected:
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
private:
@@ -42,7 +42,7 @@ KennedyScrollBarThumb::KennedyScrollBarThumb(BaseScrollBar* scroll_bar)
KennedyScrollBarThumb::~KennedyScrollBarThumb() {
}
-gfx::Size KennedyScrollBarThumb::GetPreferredSize() {
+gfx::Size KennedyScrollBarThumb::GetPreferredSize() const {
return gfx::Size(kThumbMinimumSize, kThumbMinimumSize);
}
@@ -77,7 +77,7 @@ int KennedyScrollBar::GetLayoutSize() const {
return kScrollbarWidth;
}
-gfx::Size KennedyScrollBar::GetPreferredSize() {
+gfx::Size KennedyScrollBar::GetPreferredSize() const {
return GetTrackBounds().size();
}
diff --git a/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h b/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h
index 332948387a5..ace3fae31ec 100644
--- a/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h
@@ -25,7 +25,7 @@ class VIEWS_EXPORT KennedyScrollBar : public BaseScrollBar {
virtual int GetLayoutSize() const OVERRIDE;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/native_scroll_bar.cc
index 9a913709a4b..7b45dd6e052 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar.cc
@@ -9,13 +9,10 @@
#include "base/message_loop/message_loop.h"
#include "ui/events/event.h"
+#include "ui/views/controls/scrollbar/native_scroll_bar_views.h"
#include "ui/views/controls/scrollbar/native_scroll_bar_wrapper.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/views/controls/scrollbar/native_scroll_bar_views.h"
-#endif
-
namespace views {
// static
@@ -45,7 +42,7 @@ int NativeScrollBar::GetVerticalScrollBarWidth(
////////////////////////////////////////////////////////////////////////////////
// NativeScrollBar, View overrides:
-gfx::Size NativeScrollBar::GetPreferredSize() {
+gfx::Size NativeScrollBar::GetPreferredSize() const {
if (native_wrapper_)
return native_wrapper_->GetView()->GetPreferredSize();
return gfx::Size();
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar.h b/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
index 70d5a83d37a..058784d55ac 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
@@ -40,7 +40,7 @@ class VIEWS_EXPORT NativeScrollBar : public ScrollBar {
FRIEND_TEST_ALL_PREFIXES(NativeScrollBarTest, Scrolling);
// Overridden from View.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc
index a8402e5c655..b4f83ccdf7b 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc
@@ -32,7 +32,7 @@ class ScrollBarButton : public BaseScrollBarButton {
ScrollBarButton(ButtonListener* listener, Type type);
virtual ~ScrollBarButton();
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE {
return "ScrollBarButton";
}
@@ -54,7 +54,7 @@ class ScrollBarThumb : public BaseScrollBarThumb {
explicit ScrollBarThumb(BaseScrollBar* scroll_bar);
virtual ~ScrollBarThumb();
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE {
return "ScrollBarThumb";
}
@@ -83,7 +83,7 @@ ScrollBarButton::ScrollBarButton(ButtonListener* listener, Type type)
ScrollBarButton::~ScrollBarButton() {
}
-gfx::Size ScrollBarButton::GetPreferredSize() {
+gfx::Size ScrollBarButton::GetPreferredSize() const {
return GetNativeTheme()->GetPartSize(GetNativeThemePart(),
GetNativeThemeState(),
GetNativeThemeParams());
@@ -164,7 +164,7 @@ ScrollBarThumb::ScrollBarThumb(BaseScrollBar* scroll_bar)
ScrollBarThumb::~ScrollBarThumb() {
}
-gfx::Size ScrollBarThumb::GetPreferredSize() {
+gfx::Size ScrollBarThumb::GetPreferredSize() const {
return GetNativeTheme()->GetPartSize(GetNativeThemePart(),
GetNativeThemeState(),
GetNativeThemeParams());
@@ -292,7 +292,7 @@ void NativeScrollBarViews::OnPaint(gfx::Canvas* canvas) {
GetNativeTheme()->Paint(canvas->sk_canvas(), part_, state_, bounds, params_);
}
-gfx::Size NativeScrollBarViews::GetPreferredSize() {
+gfx::Size NativeScrollBarViews::GetPreferredSize() const {
const ui::NativeTheme* theme = native_scroll_bar_->GetNativeTheme();
if (native_scroll_bar_->IsHorizontal())
return gfx::Size(0, GetHorizontalScrollBarHeight(theme));
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h
index 72d1821cbbf..38dbe0b6f8e 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h
@@ -36,7 +36,7 @@ class VIEWS_EXPORT NativeScrollBarViews : public BaseScrollBar,
// View overrides:
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
// ScrollBar overrides:
diff --git a/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc
index 176f7b9554e..1396bd1ec99 100644
--- a/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc
@@ -30,7 +30,7 @@ class OverlayScrollBarThumb : public BaseScrollBarThumb,
protected:
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
// gfx::AnimationDelegate overrides:
@@ -44,18 +44,16 @@ class OverlayScrollBarThumb : public BaseScrollBarThumb,
OverlayScrollBarThumb::OverlayScrollBarThumb(BaseScrollBar* scroll_bar)
: BaseScrollBarThumb(scroll_bar),
animation_opacity_(0.0) {
- if (get_use_acceleration_when_possible()) {
- // This is necessary, otherwise the thumb will be rendered below the views
- // if those views paint to their own layers.
- SetPaintToLayer(true);
- SetFillsBoundsOpaquely(false);
- }
+ // This is necessary, otherwise the thumb will be rendered below the views if
+ // those views paint to their own layers.
+ SetPaintToLayer(true);
+ SetFillsBoundsOpaquely(false);
}
OverlayScrollBarThumb::~OverlayScrollBarThumb() {
}
-gfx::Size OverlayScrollBarThumb::GetPreferredSize() {
+gfx::Size OverlayScrollBarThumb::GetPreferredSize() const {
return gfx::Size(kThumbMinimumSize, kThumbMinimumSize);
}
@@ -140,7 +138,7 @@ void OverlayScrollBar::OnGestureEvent(ui::GestureEvent* event) {
BaseScrollBar::OnGestureEvent(event);
}
-gfx::Size OverlayScrollBar::GetPreferredSize() {
+gfx::Size OverlayScrollBar::GetPreferredSize() const {
return gfx::Size();
}
diff --git a/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h b/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h
index b061da08586..428a27715c4 100644
--- a/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h
@@ -28,7 +28,7 @@ class VIEWS_EXPORT OverlayScrollBar : public BaseScrollBar {
virtual void OnMouseExitedScrollView(const ui::MouseEvent& event) OVERRIDE;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/views/controls/scrollbar/scroll_bar.cc b/chromium/ui/views/controls/scrollbar/scroll_bar.cc
index 5374d32ceef..014cf3b53fa 100644
--- a/chromium/ui/views/controls/scrollbar/scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/scroll_bar.cc
@@ -4,15 +4,15 @@
#include "ui/views/controls/scrollbar/scroll_bar.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
namespace views {
ScrollBar::~ScrollBar() {
}
-void ScrollBar::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_SCROLLBAR;
+void ScrollBar::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SCROLL_BAR;
}
bool ScrollBar::IsHorizontal() const {
diff --git a/chromium/ui/views/controls/scrollbar/scroll_bar.h b/chromium/ui/views/controls/scrollbar/scroll_bar.h
index aa3800eb614..c8a31c43016 100644
--- a/chromium/ui/views/controls/scrollbar/scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/scroll_bar.h
@@ -60,7 +60,7 @@ class VIEWS_EXPORT ScrollBar : public View {
virtual ~ScrollBar();
// Overridden from View:
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// Returns whether this scrollbar is horizontal.
bool IsHorizontal() const;
diff --git a/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc b/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
index cdf256a6207..c3c96df9b03 100644
--- a/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
+++ b/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
@@ -156,4 +156,15 @@ TEST_F(NativeScrollBarTest, MAYBE_ScrollBarFitsToBottom) {
scrollbar_->GetPosition());
}
+TEST_F(NativeScrollBarTest, ScrollToEndAfterShrinkAndExpand) {
+ // Scroll to the end of the content.
+ scrollbar_->Update(100, 101, 0);
+ EXPECT_TRUE(scrollbar_->ScrollByContentsOffset(-1));
+ // Shrink and then re-exapnd the content.
+ scrollbar_->Update(100, 100, 0);
+ scrollbar_->Update(100, 101, 0);
+ // Ensure the scrollbar allows scrolling to the end.
+ EXPECT_TRUE(scrollbar_->ScrollByContentsOffset(-1));
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/separator.cc b/chromium/ui/views/controls/separator.cc
index bbac3ede9de..a8fe6da7ef3 100644
--- a/chromium/ui/views/controls/separator.cc
+++ b/chromium/ui/views/controls/separator.cc
@@ -4,7 +4,7 @@
#include "ui/views/controls/separator.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
namespace views {
@@ -28,17 +28,17 @@ Separator::~Separator() {
////////////////////////////////////////////////////////////////////////////////
// Separator, View overrides:
-gfx::Size Separator::GetPreferredSize() {
+gfx::Size Separator::GetPreferredSize() const {
if (orientation_ == HORIZONTAL)
return gfx::Size(width(), kSeparatorHeight);
return gfx::Size(kSeparatorHeight, height());
}
-void Separator::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_SEPARATOR;
+void Separator::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SPLITTER;
}
-void Separator::Paint(gfx::Canvas* canvas) {
+void Separator::Paint(gfx::Canvas* canvas, const views::CullSet& cull_set) {
canvas->FillRect(bounds(), kDefaultColor);
}
diff --git a/chromium/ui/views/controls/separator.h b/chromium/ui/views/controls/separator.h
index 53d10041864..6f45f8cec7f 100644
--- a/chromium/ui/views/controls/separator.h
+++ b/chromium/ui/views/controls/separator.h
@@ -28,9 +28,10 @@ class VIEWS_EXPORT Separator : public View {
virtual ~Separator();
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
- virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual void Paint(gfx::Canvas* canvas,
+ const views::CullSet& cull_set) OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
private:
diff --git a/chromium/ui/views/controls/single_split_view.cc b/chromium/ui/views/controls/single_split_view.cc
index 85dab92fa5d..fe50141293c 100644
--- a/chromium/ui/views/controls/single_split_view.cc
+++ b/chromium/ui/views/controls/single_split_view.cc
@@ -5,14 +5,12 @@
#include "ui/views/controls/single_split_view.h"
#include "skia/ext/skia_utils_win.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
#include "ui/views/background.h"
#include "ui/views/controls/single_split_view_listener.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+#include "ui/views/native_cursor.h"
namespace views {
@@ -62,16 +60,16 @@ const char* SingleSplitView::GetClassName() const {
return kViewClassName;
}
-void SingleSplitView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_GROUPING;
+void SingleSplitView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_GROUP;
state->name = accessible_name_;
}
-gfx::Size SingleSplitView::GetPreferredSize() {
+gfx::Size SingleSplitView::GetPreferredSize() const {
int width = 0;
int height = 0;
for (int i = 0; i < 2 && i < child_count(); ++i) {
- View* view = child_at(i);
+ const View* view = child_at(i);
gfx::Size pref = view->GetPreferredSize();
if (is_horizontal_) {
width += pref.width();
@@ -91,14 +89,8 @@ gfx::Size SingleSplitView::GetPreferredSize() {
gfx::NativeCursor SingleSplitView::GetCursor(const ui::MouseEvent& event) {
if (!IsPointInDivider(event.location()))
return gfx::kNullCursor;
-#if defined(USE_AURA)
- return is_horizontal_ ?
- ui::kCursorEastWestResize : ui::kCursorNorthSouthResize;
-#elif defined(OS_WIN)
- static HCURSOR we_resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
- static HCURSOR ns_resize_cursor = LoadCursor(NULL, IDC_SIZENS);
- return is_horizontal_ ? we_resize_cursor : ns_resize_cursor;
-#endif
+ return is_horizontal_ ? GetNativeEastWestResizeCursor()
+ : GetNativeNorthSouthResizeCursor();
}
int SingleSplitView::GetDividerSize() const {
@@ -148,7 +140,7 @@ void SingleSplitView::CalculateChildrenBounds(
}
}
-void SingleSplitView::SetAccessibleName(const string16& name) {
+void SingleSplitView::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
diff --git a/chromium/ui/views/controls/single_split_view.h b/chromium/ui/views/controls/single_split_view.h
index f4a336a6ef6..c03c8340e35 100644
--- a/chromium/ui/views/controls/single_split_view.h
+++ b/chromium/ui/views/controls/single_split_view.h
@@ -34,11 +34,11 @@ class VIEWS_EXPORT SingleSplitView : public View {
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// SingleSplitView's preferred size is the sum of the preferred widths
// and the max of the heights.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Overriden to return a resize cursor when over the divider.
virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
@@ -77,7 +77,7 @@ class VIEWS_EXPORT SingleSplitView : public View {
gfx::Rect* leading_bounds,
gfx::Rect* trailing_bounds) const;
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
protected:
// View overrides.
@@ -137,7 +137,7 @@ class VIEWS_EXPORT SingleSplitView : public View {
SingleSplitViewListener* listener_;
// The accessible name of this view.
- string16 accessible_name_;
+ base::string16 accessible_name_;
DISALLOW_COPY_AND_ASSIGN(SingleSplitView);
};
diff --git a/chromium/ui/views/controls/single_split_view_listener.h b/chromium/ui/views/controls/single_split_view_listener.h
index 5c33c665214..0d589c9cfb8 100644
--- a/chromium/ui/views/controls/single_split_view_listener.h
+++ b/chromium/ui/views/controls/single_split_view_listener.h
@@ -5,13 +5,15 @@
#ifndef UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
#define UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
+#include "ui/views/views_export.h"
+
namespace views {
class SingleSplitView;
// An interface implemented by objects that want to be notified when the
// splitter moves.
-class SingleSplitViewListener {
+class VIEWS_EXPORT SingleSplitViewListener {
public:
// Invoked when split handle is moved by the user. |sender|'s divider_offset
// is already set to the new value, but Layout has not happened yet.
diff --git a/chromium/ui/views/controls/single_split_view_unittest.cc b/chromium/ui/views/controls/single_split_view_unittest.cc
index f82c1b5b090..cfea48ea4ab 100644
--- a/chromium/ui/views/controls/single_split_view_unittest.cc
+++ b/chromium/ui/views/controls/single_split_view_unittest.cc
@@ -2,15 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/controls/single_split_view.h"
+
#include "base/logging.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/views/controls/single_split_view.h"
#include "ui/views/controls/single_split_view_listener.h"
-using ::testing::_;
-using ::testing::Return;
-
namespace {
static void VerifySplitViewLayout(const views::SingleSplitView& split) {
@@ -44,9 +41,21 @@ static void VerifySplitViewLayout(const views::SingleSplitView& split) {
}
}
-class MockObserver : public views::SingleSplitViewListener {
+class SingleSplitViewListenerImpl : public views::SingleSplitViewListener {
public:
- MOCK_METHOD1(SplitHandleMoved, bool(views::SingleSplitView*));
+ SingleSplitViewListenerImpl() : count_(0) {}
+
+ virtual bool SplitHandleMoved(views::SingleSplitView* sender) OVERRIDE {
+ ++count_;
+ return false;
+ }
+
+ int count() const { return count_; }
+
+ private:
+ int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(SingleSplitViewListenerImpl);
};
class MinimumSizedView: public views::View {
@@ -55,10 +64,10 @@ class MinimumSizedView: public views::View {
private:
gfx::Size min_size_;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
};
-gfx::Size MinimumSizedView::GetMinimumSize() {
+gfx::Size MinimumSizedView::GetMinimumSize() const {
return min_size_;
}
@@ -141,20 +150,14 @@ TEST(SingleSplitViewTest, Resize) {
}
TEST(SingleSplitViewTest, MouseDrag) {
- MockObserver observer;
const int kMinimumChildSize = 25;
MinimumSizedView *child0 =
new MinimumSizedView(gfx::Size(5, kMinimumChildSize));
MinimumSizedView *child1 =
new MinimumSizedView(gfx::Size(5, kMinimumChildSize));
+ SingleSplitViewListenerImpl listener;
SingleSplitView split(
- child0, child1, SingleSplitView::VERTICAL_SPLIT, &observer);
-
- ON_CALL(observer, SplitHandleMoved(_))
- .WillByDefault(Return(true));
- // SplitHandleMoved is called for two mouse moves and one mouse capture loss.
- EXPECT_CALL(observer, SplitHandleMoved(_))
- .Times(5);
+ child0, child1, SingleSplitView::VERTICAL_SPLIT, &listener);
const int kTotalSplitSize = 100;
split.SetBounds(0, 0, 10, kTotalSplitSize);
@@ -166,49 +169,53 @@ TEST(SingleSplitViewTest, MouseDrag) {
gfx::Point press_point(7, kInitialDividerOffset + kMouseOffset);
ui::MouseEvent mouse_pressed(
- ui::ET_MOUSE_PRESSED, press_point, press_point, 0);
+ ui::ET_MOUSE_PRESSED, press_point, press_point, 0, 0);
ASSERT_TRUE(split.OnMousePressed(mouse_pressed));
EXPECT_EQ(kInitialDividerOffset, split.divider_offset());
+ EXPECT_EQ(0, listener.count());
// Drag divider to the bottom.
gfx::Point drag_1_point(
5, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta);
ui::MouseEvent mouse_dragged_1(
- ui::ET_MOUSE_DRAGGED, drag_1_point, drag_1_point, 0);
+ ui::ET_MOUSE_DRAGGED, drag_1_point, drag_1_point, 0, 0);
ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_1));
EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta, split.divider_offset());
+ EXPECT_EQ(1, listener.count());
// Drag divider to the top, beyond first child minimum size.
gfx::Point drag_2_point(
7, kMinimumChildSize - 5);
ui::MouseEvent mouse_dragged_2(
- ui::ET_MOUSE_DRAGGED, drag_2_point, drag_2_point, 0);
+ ui::ET_MOUSE_DRAGGED, drag_2_point, drag_2_point, 0,0 );
ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_2));
- EXPECT_EQ(kMinimumChildSize,
- split.divider_offset());
+ EXPECT_EQ(kMinimumChildSize, split.divider_offset());
+ EXPECT_EQ(2, listener.count());
// Drag divider to the bottom, beyond second child minimum size.
gfx::Point drag_3_point(
7, kTotalSplitSize - kMinimumChildSize + 5);
ui::MouseEvent mouse_dragged_3(
- ui::ET_MOUSE_DRAGGED, drag_3_point, drag_3_point, 0);
+ ui::ET_MOUSE_DRAGGED, drag_3_point, drag_3_point, 0, 0);
ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_3));
EXPECT_EQ(kTotalSplitSize - kMinimumChildSize - split.GetDividerSize(),
split.divider_offset());
+ EXPECT_EQ(3, listener.count());
// Drag divider between childs' minimum sizes.
gfx::Point drag_4_point(
6, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta * 2);
ui::MouseEvent mouse_dragged_4(
- ui::ET_MOUSE_DRAGGED, drag_4_point, drag_4_point, 0);
+ ui::ET_MOUSE_DRAGGED, drag_4_point, drag_4_point, 0, 0);
ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_4));
EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta * 2,
split.divider_offset());
+ EXPECT_EQ(4, listener.count());
gfx::Point release_point(
7, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta * 2);
ui::MouseEvent mouse_released(
- ui::ET_MOUSE_RELEASED, release_point, release_point, 0);
+ ui::ET_MOUSE_RELEASED, release_point, release_point, 0, 0);
split.OnMouseReleased(mouse_released);
EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta * 2,
split.divider_offset());
@@ -217,6 +224,7 @@ TEST(SingleSplitViewTest, MouseDrag) {
// This shouldn't occur after mouse release, but it's sufficient for testing.
split.OnMouseCaptureLost();
EXPECT_EQ(kInitialDividerOffset, split.divider_offset());
+ EXPECT_EQ(5, listener.count());
}
} // namespace views
diff --git a/chromium/ui/views/controls/slide_out_view.cc b/chromium/ui/views/controls/slide_out_view.cc
index d7cb3f6ef5f..d3cafecf7eb 100644
--- a/chromium/ui/views/controls/slide_out_view.cc
+++ b/chromium/ui/views/controls/slide_out_view.cc
@@ -14,10 +14,8 @@ SlideOutView::SlideOutView()
: gesture_scroll_amount_(0.f) {
// If accelerated compositing is not available, this widget tracks the
// OnSlideOut event but does not render any visible changes.
- if (get_use_acceleration_when_possible()) {
- SetPaintToLayer(true);
- SetFillsBoundsOpaquely(false);
- }
+ SetPaintToLayer(true);
+ SetFillsBoundsOpaquely(false);
}
SlideOutView::~SlideOutView() {
@@ -47,13 +45,11 @@ void SlideOutView::OnGestureEvent(ui::GestureEvent* event) {
// The scroll-update events include the incremental scroll amount.
gesture_scroll_amount_ += event->details().scroll_x();
- if (get_use_acceleration_when_possible()) {
- gfx::Transform transform;
- transform.Translate(gesture_scroll_amount_, 0.0);
- layer()->SetTransform(transform);
- layer()->SetOpacity(
- 1.f - std::min(fabsf(gesture_scroll_amount_) / width(), 1.f));
- }
+ gfx::Transform transform;
+ transform.Translate(gesture_scroll_amount_, 0.0);
+ layer()->SetTransform(transform);
+ layer()->SetOpacity(
+ 1.f - std::min(fabsf(gesture_scroll_amount_) / width(), 1.f));
} else if (event->type() == ui::ET_GESTURE_SCROLL_END) {
const float kScrollRatioForClosingNotification = 0.5f;
@@ -70,9 +66,6 @@ void SlideOutView::OnGestureEvent(ui::GestureEvent* event) {
}
void SlideOutView::RestoreVisualState() {
- if (!get_use_acceleration_when_possible())
- return;
-
// Restore the layer state.
const int kSwipeRestoreDurationMS = 150;
ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
@@ -83,11 +76,6 @@ void SlideOutView::RestoreVisualState() {
}
void SlideOutView::SlideOutAndClose(SlideDirection direction) {
- if (!get_use_acceleration_when_possible()) {
- // No animations, so don't wait to fire the OnSlideOut event.
- OnSlideOut();
- return;
- }
const int kSwipeOutTotalDurationMS = 150;
int swipe_out_duration = kSwipeOutTotalDurationMS * layer()->opacity();
ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
diff --git a/chromium/ui/views/controls/slider.cc b/chromium/ui/views/controls/slider.cc
index 4be6f5a2d56..74e803d454b 100644
--- a/chromium/ui/views/controls/slider.cc
+++ b/chromium/ui/views/controls/slider.cc
@@ -4,6 +4,8 @@
#include "ui/views/controls/slider.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
@@ -12,7 +14,7 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPaint.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
#include "ui/gfx/animation/slide_animation.h"
@@ -45,7 +47,7 @@ enum BorderElements {
CENTER_RIGHT,
RIGHT,
};
-}
+} // namespace
namespace views {
@@ -81,7 +83,7 @@ void Slider::SetValueInternal(float value, SliderChangeReason reason) {
value_is_valid_ = true;
if (value < 0.0)
- value = 0.0;
+ value = 0.0;
else if (value > 1.0)
value = 1.0;
if (value_ == value)
@@ -104,7 +106,7 @@ void Slider::SetValueInternal(float value, SliderChangeReason reason) {
}
if (accessibility_events_enabled_ && GetWidget()) {
NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_VALUE_CHANGED, true);
+ ui::AX_EVENT_VALUE_CHANGED, true);
}
}
@@ -167,7 +169,7 @@ void Slider::UpdateState(bool control_on) {
SchedulePaint();
}
-void Slider::SetAccessibleName(const string16& name) {
+void Slider::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
@@ -184,7 +186,7 @@ void Slider::OnPaintFocus(gfx::Canvas* canvas) {
}
}
-gfx::Size Slider::GetPreferredSize() {
+gfx::Size Slider::GetPreferredSize() const {
const int kSizeMajor = 200;
const int kSizeMinor = 40;
@@ -267,8 +269,7 @@ void Slider::OnPaint(gfx::Canvas* canvas) {
bool Slider::OnMousePressed(const ui::MouseEvent& event) {
if (!event.IsOnlyLeftMouseButton())
return false;
- if (listener_)
- listener_->SliderDragStarted(this);
+ OnSliderDragStarted();
PrepareForMove(event.location());
MoveButtonTo(event.location());
return true;
@@ -280,8 +281,7 @@ bool Slider::OnMouseDragged(const ui::MouseEvent& event) {
}
void Slider::OnMouseReleased(const ui::MouseEvent& event) {
- if (listener_)
- listener_->SliderDragEnded(this);
+ OnSliderDragEnded();
}
bool Slider::OnKeyPressed(const ui::KeyEvent& event) {
@@ -305,16 +305,37 @@ bool Slider::OnKeyPressed(const ui::KeyEvent& event) {
return false;
}
+void Slider::OnFocus() {
+ View::OnFocus();
+ SchedulePaint();
+}
+
+void Slider::OnBlur() {
+ View::OnBlur();
+ SchedulePaint();
+}
+
void Slider::OnGestureEvent(ui::GestureEvent* event) {
- if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN ||
- event->type() == ui::ET_GESTURE_TAP_DOWN) {
- PrepareForMove(event->location());
- MoveButtonTo(event->location());
- event->SetHandled();
- } else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE ||
- event->type() == ui::ET_GESTURE_SCROLL_END) {
- MoveButtonTo(event->location());
- event->SetHandled();
+ switch (event->type()) {
+ // In a multi point gesture only the touch point will generate
+ // an ET_GESTURE_TAP_DOWN event.
+ case ui::ET_GESTURE_TAP_DOWN:
+ OnSliderDragStarted();
+ PrepareForMove(event->location());
+ // Intentional fall through to next case.
+ case ui::ET_GESTURE_SCROLL_BEGIN:
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ MoveButtonTo(event->location());
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_END:
+ MoveButtonTo(event->location());
+ event->SetHandled();
+ if (event->details().touch_points() <= 1)
+ OnSliderDragEnded();
+ break;
+ default:
+ break;
}
}
@@ -323,11 +344,21 @@ void Slider::AnimationProgressed(const gfx::Animation* animation) {
SchedulePaint();
}
-void Slider::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_SLIDER;
+void Slider::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SLIDER;
state->name = accessible_name_;
- state->value = UTF8ToUTF16(
- base::StringPrintf("%d%%", (int)(value_ * 100 + 0.5)));
+ state->value = base::UTF8ToUTF16(
+ base::StringPrintf("%d%%", static_cast<int>(value_ * 100 + 0.5)));
+}
+
+void Slider::OnSliderDragStarted() {
+ if (listener_)
+ listener_->SliderDragStarted(this);
+}
+
+void Slider::OnSliderDragEnded() {
+ if (listener_)
+ listener_->SliderDragEnded(this);
}
} // namespace views
diff --git a/chromium/ui/views/controls/slider.h b/chromium/ui/views/controls/slider.h
index cec24c2755b..33a760bfd66 100644
--- a/chromium/ui/views/controls/slider.h
+++ b/chromium/ui/views/controls/slider.h
@@ -18,6 +18,10 @@ class SlideAnimation;
namespace views {
+namespace test {
+class SliderTestApi;
+}
+
class Slider;
enum SliderChangeReason {
@@ -57,7 +61,7 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
// Set the delta used for changing the value via keyboard.
void SetKeyboardIncrement(float increment);
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
void set_enable_accessibility_events(bool enabled) {
accessibility_events_enabled_ = enabled;
@@ -69,6 +73,8 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
void UpdateState(bool control_on);
private:
+ friend class test::SliderTestApi;
+
void SetValueInternal(float value, SliderChangeReason reason);
// Should be called on the Mouse Down event. Used to calculate relative
@@ -81,14 +87,22 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
void OnPaintFocus(gfx::Canvas* canvas);
+ // Notify the listener_, if not NULL, that dragging started.
+ void OnSliderDragStarted();
+
+ // Notify the listener_, if not NULL, that dragging ended.
+ void OnSliderDragEnded();
+
// views::View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual void OnFocus() OVERRIDE;
+ virtual void OnBlur() OVERRIDE;
// ui::EventHandler overrides:
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
@@ -96,6 +110,10 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
// gfx::AnimationDelegate overrides:
virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
+ void set_listener(SliderListener* listener) {
+ listener_ = listener;
+ }
+
SliderListener* listener_;
Orientation orientation_;
@@ -105,7 +123,7 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
float keyboard_increment_;
float animating_value_;
bool value_is_valid_;
- string16 accessible_name_;
+ base::string16 accessible_name_;
bool accessibility_events_enabled_;
SkColor focus_border_color_;
diff --git a/chromium/ui/views/controls/slider_unittest.cc b/chromium/ui/views/controls/slider_unittest.cc
index 7add734ec36..da6700e0f72 100644
--- a/chromium/ui/views/controls/slider_unittest.cc
+++ b/chromium/ui/views/controls/slider_unittest.cc
@@ -4,73 +4,381 @@
#include "ui/views/controls/slider.h"
+#include <string>
+
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/events/event.h"
+#include "ui/events/gesture_event_details.h"
+#include "ui/views/test/slider_test_api.h"
+#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
namespace {
-void ClickAt(views::View* view, int x, int y) {
- gfx::Point point(x, y);
- ui::MouseEvent press(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- view->OnMousePressed(press);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- view->OnMouseReleased(release);
+// A views::SliderListener that tracks simple event call history.
+class TestSliderListener : public views::SliderListener {
+ public:
+ TestSliderListener();
+ virtual ~TestSliderListener();
+
+ int last_event_epoch() {
+ return last_event_epoch_;
+ }
+
+ int last_drag_started_epoch() {
+ return last_drag_started_epoch_;
+ }
+
+ int last_drag_ended_epoch() {
+ return last_drag_ended_epoch_;
+ }
+
+ views::Slider* last_drag_started_sender() {
+ return last_drag_started_sender_;
+ }
+
+ views::Slider* last_drag_ended_sender() {
+ return last_drag_ended_sender_;
+ }
+
+ // Resets the state of this as if it were newly created.
+ virtual void ResetCallHistory();
+
+ // views::SliderListener:
+ virtual void SliderValueChanged(views::Slider* sender,
+ float value,
+ float old_value,
+ views::SliderChangeReason reason) OVERRIDE;
+ virtual void SliderDragStarted(views::Slider* sender) OVERRIDE;
+ virtual void SliderDragEnded(views::Slider* sender) OVERRIDE;
+
+ private:
+ // The epoch of the last event.
+ int last_event_epoch_;
+ // The epoch of the last time SliderDragStarted was called.
+ int last_drag_started_epoch_;
+ // The epoch of the last time SliderDragEnded was called.
+ int last_drag_ended_epoch_;
+ // The sender from the last SliderDragStarted call.
+ views::Slider* last_drag_started_sender_;
+ // The sender from the last SliderDragEnded call.
+ views::Slider* last_drag_ended_sender_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSliderListener);
+};
+
+TestSliderListener::TestSliderListener()
+ : last_event_epoch_(0),
+ last_drag_started_epoch_(-1),
+ last_drag_ended_epoch_(-1),
+ last_drag_started_sender_(NULL),
+ last_drag_ended_sender_(NULL) {
+}
+
+TestSliderListener::~TestSliderListener() {
+ last_drag_started_sender_ = NULL;
+ last_drag_ended_sender_ = NULL;
+}
+
+void TestSliderListener::ResetCallHistory() {
+ last_event_epoch_ = 0;
+ last_drag_started_epoch_ = -1;
+ last_drag_ended_epoch_ = -1;
+ last_drag_started_sender_ = NULL;
+ last_drag_ended_sender_ = NULL;
+}
+
+void TestSliderListener::SliderValueChanged(views::Slider* sender,
+ float value,
+ float old_value,
+ views::SliderChangeReason reason) {
+ ++last_event_epoch_;
+}
+
+void TestSliderListener::SliderDragStarted(views::Slider* sender) {
+ last_drag_started_sender_ = sender;
+ last_drag_started_epoch_ = ++last_event_epoch_;
}
+void TestSliderListener::SliderDragEnded(views::Slider* sender) {
+ last_drag_ended_sender_ = sender;
+ last_drag_ended_epoch_ = ++last_event_epoch_;
}
+} // namespace
+
namespace views {
-TEST(SliderTest, UpdateFromClickHorizontal) {
- scoped_ptr<Slider> slider(new Slider(NULL, Slider::HORIZONTAL));
- View* view = slider.get();
- gfx::Size size = view->GetPreferredSize();
- view->SetSize(size);
+// Base test fixture for Slider tests.
+class SliderTest : public views::ViewsTestBase {
+ public:
+ explicit SliderTest(Slider::Orientation orientation);
+ virtual ~SliderTest();
+
+ protected:
+ Slider* slider() {
+ return slider_;
+ }
+
+ TestSliderListener& slider_listener() {
+ return slider_listener_;
+ }
+
+ int max_x() {
+ return max_x_;
+ }
+
+ int max_y() {
+ return max_y_;
+ }
+
+ virtual void ClickAt(int x, int y);
+
+ // testing::Test:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ aura::test::EventGenerator* event_generator() {
+ return event_generator_.get();
+ }
- ClickAt(view, 0, 0);
- EXPECT_EQ(0.0f, slider->value());
+ private:
+ // The Slider's orientation
+ Slider::Orientation orientation_;
+ // The Slider to be tested.
+ Slider* slider_;
+ // A simple SliderListener test double.
+ TestSliderListener slider_listener_;
+ // Stores the default locale at test setup so it can be restored
+ // during test teardown.
+ std::string default_locale_;
+ // The maximum x value within the bounds of the slider.
+ int max_x_;
+ // The maximum y value within the bounds of the slider.
+ int max_y_;
+ // The widget container for the slider being tested.
+ views::Widget* widget_;
+ // An event generator.
+ scoped_ptr<aura::test::EventGenerator> event_generator_;
- ClickAt(view, view->width(), 0);
- EXPECT_EQ(1.0f, slider->value());
+ DISALLOW_COPY_AND_ASSIGN(SliderTest);
+};
+
+SliderTest::SliderTest(Slider::Orientation orientation)
+ : orientation_(orientation),
+ slider_(NULL),
+ default_locale_(""),
+ max_x_(0),
+ max_y_(0) {
+}
+
+SliderTest::~SliderTest() {
}
-TEST(SliderTest, UpdateFromClickVertical) {
- scoped_ptr<Slider> slider(new Slider(NULL, Slider::VERTICAL));
- View* view = slider.get();
+void SliderTest::SetUp() {
+ views::ViewsTestBase::SetUp();
+
+ slider_ = new Slider(NULL, orientation_);
+ View* view = slider_;
gfx::Size size = view->GetPreferredSize();
view->SetSize(size);
+ max_x_ = size.width() - 1;
+ max_y_ = size.height() - 1;
+ default_locale_ = l10n_util::GetApplicationLocale("");
+
+ views::Widget::InitParams init_params(CreateParams(
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS));
+ init_params.bounds = gfx::Rect(size);
- ClickAt(view, 0, 0);
- EXPECT_EQ(1.0f, slider->value());
+ widget_ = new views::Widget();
+ widget_->Init(init_params);
+ widget_->SetContentsView(slider_);
+ widget_->Show();
- ClickAt(view, 0, view->height());
- EXPECT_EQ(0.0f, slider->value());
+ aura::Window* native_window = widget_->GetNativeWindow();
+ event_generator_.reset(new aura::test::EventGenerator(
+ native_window->GetRootWindow()));
}
-TEST(SliderTest, UpdateFromClickRTLHorizontal) {
- std::string locale = l10n_util::GetApplicationLocale("");
+void SliderTest::TearDown() {
+ if (widget_ && !widget_->IsClosed())
+ widget_->Close();
+
+ base::i18n::SetICUDefaultLocale(default_locale_);
+
+ views::ViewsTestBase::TearDown();
+}
+
+void SliderTest::ClickAt(int x, int y) {
+ gfx::Point point(x, y);
+ event_generator_->MoveMouseTo(point);
+ event_generator_->ClickLeftButton();
+}
+
+// Test fixture for horizontally oriented slider tests.
+class HorizontalSliderTest : public SliderTest {
+ public:
+ HorizontalSliderTest();
+ virtual ~HorizontalSliderTest();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HorizontalSliderTest);
+};
+
+HorizontalSliderTest::HorizontalSliderTest()
+ : SliderTest(Slider::HORIZONTAL) {
+}
+
+HorizontalSliderTest::~HorizontalSliderTest() {
+}
+
+// Test fixture for vertically oriented slider tests.
+class VerticalSliderTest : public SliderTest {
+ public:
+ VerticalSliderTest();
+ virtual ~VerticalSliderTest();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VerticalSliderTest);
+};
+
+VerticalSliderTest::VerticalSliderTest()
+ : SliderTest(Slider::VERTICAL) {
+}
+
+VerticalSliderTest::~VerticalSliderTest() {
+}
+
+TEST_F(HorizontalSliderTest, UpdateFromClickHorizontal) {
+ ClickAt(0, 0);
+ EXPECT_EQ(0.0f, slider()->value());
+
+ ClickAt(max_x(), 0);
+ EXPECT_EQ(1.0f, slider()->value());
+}
+
+TEST_F(VerticalSliderTest, UpdateFromClickVertical) {
+ ClickAt(0, 0);
+ EXPECT_EQ(1.0f, slider()->value());
+
+ ClickAt(0, max_y());
+ EXPECT_EQ(0.0f, slider()->value());
+}
+
+TEST_F(HorizontalSliderTest, UpdateFromClickRTLHorizontal) {
base::i18n::SetICUDefaultLocale("he");
- scoped_ptr<Slider> slider(new Slider(NULL, Slider::HORIZONTAL));
- View* view = slider.get();
- gfx::Size size = view->GetPreferredSize();
- view->SetSize(size);
+ ClickAt(0, 0);
+ EXPECT_EQ(1.0f, slider()->value());
+
+ ClickAt(max_x(), 0);
+ EXPECT_EQ(0.0f, slider()->value());
+}
+
+// Test the slider location after a tap gesture.
+TEST_F(HorizontalSliderTest, SliderValueForTapGesture) {
+ // Tap below the minimum.
+ slider()->SetValue(0.5);
+ event_generator()->GestureTapAt(gfx::Point(0, 0));
+ EXPECT_FLOAT_EQ(0, slider()->value());
+
+ // Tap above the maximum.
+ slider()->SetValue(0.5);
+ event_generator()->GestureTapAt(gfx::Point(max_x(), max_y()));
+ EXPECT_FLOAT_EQ(1, slider()->value());
+
+ // Tap somwhere in the middle.
+ slider()->SetValue(0.5);
+ event_generator()->GestureTapAt(gfx::Point(0.75 * max_x(), 0.75 * max_y()));
+ EXPECT_NEAR(0.75, slider()->value(), 0.03);
+}
+
+// Test the slider location after a scroll gesture.
+TEST_F(HorizontalSliderTest, SliderValueForScrollGesture) {
+ // Scroll below the minimum.
+ slider()->SetValue(0.5);
+ event_generator()->GestureScrollSequence(
+ gfx::Point(0.5 * max_x(), 0.5 * max_y()),
+ gfx::Point(0, 0),
+ base::TimeDelta::FromMilliseconds(10),
+ 5 /* steps */);
+ EXPECT_EQ(0, slider()->value());
+
+ // Scroll above the maximum.
+ slider()->SetValue(0.5);
+ event_generator()->GestureScrollSequence(
+ gfx::Point(0.5 * max_x(), 0.5 * max_y()),
+ gfx::Point(max_x(), max_y()),
+ base::TimeDelta::FromMilliseconds(10),
+ 5 /* steps */);
+ EXPECT_EQ(1, slider()->value());
+
+ // Scroll somewhere in the middle.
+ slider()->SetValue(0.25);
+ event_generator()->GestureScrollSequence(
+ gfx::Point(0.25 * max_x(), 0.25 * max_y()),
+ gfx::Point(0.75 * max_x(), 0.75 * max_y()),
+ base::TimeDelta::FromMilliseconds(10),
+ 5 /* steps */);
+ EXPECT_NEAR(0.75, slider()->value(), 0.03);
+}
+
+// Verifies the correct SliderListener events are raised for a tap gesture.
+TEST_F(HorizontalSliderTest, SliderListenerEventsForTapGesture) {
+ test::SliderTestApi slider_test_api(slider());
+ slider_test_api.SetListener(&slider_listener());
+
+ event_generator()->GestureTapAt(gfx::Point(0, 0));
+ EXPECT_EQ(1, slider_listener().last_drag_started_epoch());
+ EXPECT_EQ(2, slider_listener().last_drag_ended_epoch());
+ EXPECT_EQ(slider(), slider_listener().last_drag_started_sender());
+ EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender());
+}
+
+// Verifies the correct SliderListener events are raised for a scroll gesture.
+TEST_F(HorizontalSliderTest, SliderListenerEventsForScrollGesture) {
+ test::SliderTestApi slider_test_api(slider());
+ slider_test_api.SetListener(&slider_listener());
+
+ event_generator()->GestureScrollSequence(
+ gfx::Point(0.25 * max_x(), 0.25 * max_y()),
+ gfx::Point(0.75 * max_x(), 0.75 * max_y()),
+ base::TimeDelta::FromMilliseconds(0),
+ 5 /* steps */);
+
+ EXPECT_EQ(1, slider_listener().last_drag_started_epoch());
+ EXPECT_GT(slider_listener().last_drag_ended_epoch(),
+ slider_listener().last_drag_started_epoch());
+ EXPECT_EQ(slider(), slider_listener().last_drag_started_sender());
+ EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender());
+}
- ClickAt(view, 0, 0);
- EXPECT_EQ(1.0f, slider->value());
+// Verifies the correct SliderListener events are raised for a multi
+// finger scroll gesture.
+TEST_F(HorizontalSliderTest, SliderListenerEventsForMultiFingerScrollGesture) {
+ test::SliderTestApi slider_test_api(slider());
+ slider_test_api.SetListener(&slider_listener());
- ClickAt(view, view->width(), 0);
- EXPECT_EQ(0.0f, slider->value());
+ gfx::Point points[] = {gfx::Point(0, 0.1 * max_y()),
+ gfx::Point(0, 0.2 * max_y())};
+ event_generator()->GestureMultiFingerScroll(2 /* count */, points,
+ 0 /* event_separation_time_ms */, 5 /* steps */,
+ 2 /* move_x */, 0 /* move_y */);
- // Reset locale.
- base::i18n::SetICUDefaultLocale(locale);
+ EXPECT_EQ(1, slider_listener().last_drag_started_epoch());
+ EXPECT_GT(slider_listener().last_drag_ended_epoch(),
+ slider_listener().last_drag_started_epoch());
+ EXPECT_EQ(slider(), slider_listener().last_drag_started_sender());
+ EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender());
}
} // namespace views
diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc
index 96cc275c2d1..e7ee56c0b44 100644
--- a/chromium/ui/views/controls/styled_label.cc
+++ b/chromium/ui/views/controls/styled_label.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/strings/string_util.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/text_elider.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/label.h"
@@ -15,17 +16,22 @@
namespace views {
+
+// Helpers --------------------------------------------------------------------
+
namespace {
// Calculates the height of a line of text. Currently returns the height of
// a label.
-int CalculateLineHeight() {
+int CalculateLineHeight(const gfx::FontList& font_list) {
Label label;
+ label.SetFontList(font_list);
return label.GetPreferredSize().height();
}
scoped_ptr<Label> CreateLabelRange(
- const string16& text,
+ const base::string16& text,
+ const gfx::FontList& font_list,
const StyledLabel::RangeStyleInfo& style_info,
views::LinkListener* link_listener) {
scoped_ptr<Label> result;
@@ -36,26 +42,27 @@ scoped_ptr<Label> CreateLabelRange(
link->SetUnderline((style_info.font_style & gfx::Font::UNDERLINE) != 0);
result.reset(link);
} else {
- Label* label = new Label(text);
- // Give the label a focus border so that its preferred size matches
- // links' preferred sizes
- label->SetHasFocusBorder(true);
-
- result.reset(label);
+ result.reset(new Label(text));
}
result->SetEnabledColor(style_info.color);
+ result->SetFontList(font_list);
if (!style_info.tooltip.empty())
result->SetTooltipText(style_info.tooltip);
- if (style_info.font_style != gfx::Font::NORMAL)
- result->SetFont(result->font().DeriveFont(0, style_info.font_style));
+ if (style_info.font_style != gfx::Font::NORMAL) {
+ result->SetFontList(
+ result->font_list().DeriveWithStyle(style_info.font_style));
+ }
- return scoped_ptr<Label>(result.release());
+ return result.Pass();
}
} // namespace
+
+// StyledLabel::RangeStyleInfo ------------------------------------------------
+
StyledLabel::RangeStyleInfo::RangeStyleInfo()
: font_style(gfx::Font::NORMAL),
color(ui::NativeTheme::instance()->GetSystemColor(
@@ -74,35 +81,49 @@ StyledLabel::RangeStyleInfo StyledLabel::RangeStyleInfo::CreateForLink() {
return result;
}
+
+// StyledLabel::StyleRange ----------------------------------------------------
+
bool StyledLabel::StyleRange::operator<(
const StyledLabel::StyleRange& other) const {
- // Intentionally reversed so the priority queue is sorted by smallest first.
- return range.start() > other.range.start();
+ return range.start() < other.range.start();
}
-StyledLabel::StyledLabel(const string16& text, StyledLabelListener* listener)
+
+// StyledLabel ----------------------------------------------------------------
+
+StyledLabel::StyledLabel(const base::string16& text,
+ StyledLabelListener* listener)
: listener_(listener),
displayed_on_background_color_set_(false),
auto_color_readability_enabled_(true) {
- TrimWhitespace(text, TRIM_TRAILING, &text_);
+ base::TrimWhitespace(text, base::TRIM_TRAILING, &text_);
}
StyledLabel::~StyledLabel() {}
-void StyledLabel::SetText(const string16& text) {
+void StyledLabel::SetText(const base::string16& text) {
text_ = text;
- style_ranges_ = std::priority_queue<StyleRange>();
+ style_ranges_.clear();
RemoveAllChildViews(true);
PreferredSizeChanged();
}
+void StyledLabel::SetBaseFontList(const gfx::FontList& font_list) {
+ font_list_ = font_list;
+ PreferredSizeChanged();
+}
+
void StyledLabel::AddStyleRange(const gfx::Range& range,
const RangeStyleInfo& style_info) {
DCHECK(!range.is_reversed());
DCHECK(!range.is_empty());
DCHECK(gfx::Range(0, text_.size()).Contains(range));
- style_ranges_.push(StyleRange(range, style_info));
+ // Insert the new range in sorted order.
+ StyleRanges new_range;
+ new_range.push_front(StyleRange(range, style_info));
+ style_ranges_.merge(new_range);
PreferredSizeChanged();
}
@@ -119,20 +140,37 @@ void StyledLabel::SetDisplayedOnBackgroundColor(SkColor color) {
gfx::Insets StyledLabel::GetInsets() const {
gfx::Insets insets = View::GetInsets();
- const gfx::Insets focus_border_padding(1, 1, 1, 1);
- insets += focus_border_padding;
+
+ // We need a focus border iff we contain a link that will have a focus border.
+ // That in turn will be true only if the link is non-empty.
+ for (StyleRanges::const_iterator i(style_ranges_.begin());
+ i != style_ranges_.end(); ++i) {
+ if (i->style_info.is_link && !i->range.is_empty()) {
+ const gfx::Insets focus_border_padding(
+ Label::kFocusBorderPadding, Label::kFocusBorderPadding,
+ Label::kFocusBorderPadding, Label::kFocusBorderPadding);
+ insets += focus_border_padding;
+ break;
+ }
+ }
+
return insets;
}
-int StyledLabel::GetHeightForWidth(int w) {
- if (w != calculated_size_.width())
- calculated_size_ = gfx::Size(w, CalculateAndDoLayout(w, true));
-
+int StyledLabel::GetHeightForWidth(int w) const {
+ if (w != calculated_size_.width()) {
+ // TODO(erg): Munge the const-ness of the style label. CalculateAndDoLayout
+ // doesn't actually make any changes to member variables when |dry_run| is
+ // set to true. In general, the mutating and non-mutating parts shouldn't
+ // be in the same codepath.
+ calculated_size_ =
+ const_cast<StyledLabel*>(this)->CalculateAndDoLayout(w, true);
+ }
return calculated_size_.height();
}
void StyledLabel::Layout() {
- CalculateAndDoLayout(GetLocalBounds().width(), false);
+ calculated_size_ = CalculateAndDoLayout(GetLocalBounds().width(), false);
}
void StyledLabel::PreferredSizeChanged() {
@@ -145,7 +183,7 @@ void StyledLabel::LinkClicked(Link* source, int event_flags) {
listener_->StyledLabelLinkClicked(link_targets_[source], event_flags);
}
-int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
+gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
if (!dry_run) {
RemoveAllChildViews(true);
link_targets_.clear();
@@ -153,41 +191,43 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
width -= GetInsets().width();
if (width <= 0 || text_.empty())
- return 0;
+ return gfx::Size();
- const int line_height = CalculateLineHeight();
+ const int line_height = CalculateLineHeight(font_list_);
// The index of the line we're on.
int line = 0;
// The x position (in pixels) of the line we're on, relative to content
// bounds.
int x = 0;
- string16 remaining_string = text_;
- std::priority_queue<StyleRange> style_ranges = style_ranges_;
+ base::string16 remaining_string = text_;
+ StyleRanges::const_iterator current_range = style_ranges_.begin();
// Iterate over the text, creating a bunch of labels and links and laying them
// out in the appropriate positions.
while (!remaining_string.empty()) {
// Don't put whitespace at beginning of a line with an exception for the
// first line (so the text's leading whitespace is respected).
- if (x == 0 && line > 0)
- TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
+ if (x == 0 && line > 0) {
+ base::TrimWhitespace(remaining_string, base::TRIM_LEADING,
+ &remaining_string);
+ }
gfx::Range range(gfx::Range::InvalidRange());
- if (!style_ranges.empty())
- range = style_ranges.top().range;
+ if (current_range != style_ranges_.end())
+ range = current_range->range;
const size_t position = text_.size() - remaining_string.size();
const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height);
- std::vector<string16> substrings;
- gfx::FontList text_font_list;
+ std::vector<base::string16> substrings;
+ gfx::FontList text_font_list = font_list_;
// If the start of the remaining text is inside a styled range, the font
// style may differ from the base font. The font specified by the range
// should be used when eliding text.
if (position >= range.start()) {
- text_font_list = text_font_list.DeriveFontListWithSizeDeltaAndStyle(
- 0, style_ranges.top().style_info.font_style);
+ text_font_list = text_font_list.DeriveWithStyle(
+ current_range->style_info.font_style);
}
gfx::ElideRectangleText(remaining_string,
text_font_list,
@@ -197,7 +237,7 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
&substrings);
DCHECK(!substrings.empty());
- string16 chunk = substrings[0];
+ base::string16 chunk = substrings[0];
if (chunk.empty()) {
// Nothing fits on this line. Start a new line.
// If x is 0, first line may have leading whitespace that doesn't fit in a
@@ -205,7 +245,8 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
// anything; abort.
if (x == 0) {
if (line == 0) {
- TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
+ base::TrimWhitespace(remaining_string, base::TRIM_LEADING,
+ &remaining_string);
continue;
}
break;
@@ -218,7 +259,7 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
scoped_ptr<Label> label;
if (position >= range.start()) {
- const RangeStyleInfo& style_info = style_ranges.top().style_info;
+ const RangeStyleInfo& style_info = current_range->style_info;
if (style_info.disable_line_wrapping && chunk.size() < range.length() &&
position == range.start() && x != 0) {
@@ -231,42 +272,44 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
chunk = chunk.substr(0, std::min(chunk.size(), range.end() - position));
- label = CreateLabelRange(chunk, style_info, this);
+ label = CreateLabelRange(chunk, font_list_, style_info, this);
if (style_info.is_link && !dry_run)
link_targets_[label.get()] = range;
if (position + chunk.size() >= range.end())
- style_ranges.pop();
+ ++current_range;
} else {
// This chunk is normal text.
if (position + chunk.size() > range.start())
chunk = chunk.substr(0, range.start() - position);
- label = CreateLabelRange(chunk, default_style_info_, this);
+ label = CreateLabelRange(chunk, font_list_, default_style_info_, this);
}
if (displayed_on_background_color_set_)
label->SetBackgroundColor(displayed_on_background_color_);
label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_);
- // Lay out the views to overlap by 1 pixel to compensate for their border
- // spacing. Otherwise, "<a>link</a>," will render as "link ,".
- const int overlap = 1;
+ // Calculate the size of the optional focus border, and overlap by that
+ // amount. Otherwise, "<a>link</a>," will render as "link ,".
+ gfx::Insets focus_border_insets(label->GetInsets());
+ focus_border_insets += -label->View::GetInsets();
const gfx::Size view_size = label->GetPreferredSize();
- DCHECK_EQ(line_height, view_size.height() - 2 * overlap);
+ DCHECK_EQ(line_height, view_size.height() - focus_border_insets.height());
if (!dry_run) {
label->SetBoundsRect(gfx::Rect(
- gfx::Point(GetInsets().left() + x - overlap,
- GetInsets().top() + line * line_height - overlap),
+ gfx::Point(GetInsets().left() + x - focus_border_insets.left(),
+ GetInsets().top() + line * line_height -
+ focus_border_insets.top()),
view_size));
AddChildView(label.release());
}
- x += view_size.width() - 2 * overlap;
+ x += view_size.width() - focus_border_insets.width();
remaining_string = remaining_string.substr(chunk.size());
}
- return (line + 1) * line_height + GetInsets().height();
+ return gfx::Size(width, (line + 1) * line_height + GetInsets().height());
}
} // namespace views
diff --git a/chromium/ui/views/controls/styled_label.h b/chromium/ui/views/controls/styled_label.h
index adf5993a767..4c599a0d438 100644
--- a/chromium/ui/views/controls/styled_label.h
+++ b/chromium/ui/views/controls/styled_label.h
@@ -5,12 +5,13 @@
#ifndef UI_VIEWS_CONTROLS_STYLED_LABEL_H_
#define UI_VIEWS_CONTROLS_STYLED_LABEL_H_
+#include <list>
#include <map>
-#include <queue>
#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/size.h"
#include "ui/views/controls/link_listener.h"
@@ -44,7 +45,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
SkColor color;
// Tooltip for the range.
- string16 tooltip;
+ base::string16 tooltip;
// If set, the whole range will be put on a single line.
bool disable_line_wrapping;
@@ -54,11 +55,15 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
};
// Note that any trailing whitespace in |text| will be trimmed.
- StyledLabel(const string16& text, StyledLabelListener* listener);
+ StyledLabel(const base::string16& text, StyledLabelListener* listener);
virtual ~StyledLabel();
// Sets the text to be displayed, and clears any previous styling.
- void SetText(const string16& text);
+ void SetText(const base::string16& text);
+
+ // Sets the fonts used by all labels. Can be augemented by styling set by
+ // AddStyleRange and SetDefaultStyle.
+ void SetBaseFontList(const gfx::FontList& font_list);
// Marks the given range within |text_| with style defined by |style_info|.
// |range| must be contained in |text_|.
@@ -82,7 +87,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
// View implementation:
virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual int GetHeightForWidth(int w) OVERRIDE;
+ virtual int GetHeightForWidth(int w) const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void PreferredSizeChanged() OVERRIDE;
@@ -103,15 +108,19 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
gfx::Range range;
RangeStyleInfo style_info;
};
+ typedef std::list<StyleRange> StyleRanges;
// Calculates how to layout child views, creates them and sets their size
// and position. |width| is the horizontal space, in pixels, that the view
// has to work with. If |dry_run| is true, the view hierarchy is not touched.
- // The return value is the height in pixels.
- int CalculateAndDoLayout(int width, bool dry_run);
+ // The return value is the necessary size.
+ gfx::Size CalculateAndDoLayout(int width, bool dry_run);
// The text to display.
- string16 text_;
+ base::string16 text_;
+
+ // Fonts used to display text. Can be augmented by RangeStyleInfo.
+ gfx::FontList font_list_;
// The default style to use for any part of the text that isn't within
// a range in |style_ranges_|.
@@ -121,7 +130,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
StyledLabelListener* listener_;
// The ranges that should be linkified, sorted by start position.
- std::priority_queue<StyleRange> style_ranges_;
+ StyleRanges style_ranges_;
// A mapping from a view to the range it corresponds to in |text_|. Only views
// that correspond to ranges with is_link style set will be added to the map.
@@ -129,7 +138,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
// This variable saves the result of the last GetHeightForWidth call in order
// to avoid repeated calculation.
- gfx::Size calculated_size_;
+ mutable gfx::Size calculated_size_;
// Background color on which the label is drawn, for auto color readability.
SkColor displayed_on_background_color_;
diff --git a/chromium/ui/views/controls/styled_label_unittest.cc b/chromium/ui/views/controls/styled_label_unittest.cc
index 18595edf3d5..d360aedb1b0 100644
--- a/chromium/ui/views/controls/styled_label_unittest.cc
+++ b/chromium/ui/views/controls/styled_label_unittest.cc
@@ -9,14 +9,19 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/border.h"
#include "ui/views/controls/link.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/controls/styled_label_listener.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget.h"
+
+using base::ASCIIToUTF16;
namespace views {
-class StyledLabelTest : public testing::Test, public StyledLabelListener {
+class StyledLabelTest : public ViewsTestBase, public StyledLabelListener {
public:
StyledLabelTest() {}
virtual ~StyledLabelTest() {}
@@ -30,6 +35,7 @@ class StyledLabelTest : public testing::Test, public StyledLabelListener {
void InitStyledLabel(const std::string& ascii_text) {
styled_.reset(new StyledLabel(ASCIIToUTF16(ascii_text), this));
+ styled_->set_owned_by_client();
}
int StyledLabelContentHeightForWidth(int w) {
@@ -105,7 +111,7 @@ TEST_F(StyledLabelTest, BasicWrapping) {
StyledLabelContentHeightForWidth(label_preferred_size.width()));
// Also respect the border.
- styled()->set_border(Border::CreateEmptyBorder(3, 3, 3, 3));
+ styled()->SetBorder(Border::CreateEmptyBorder(3, 3, 3, 3));
styled()->SetBounds(
0,
0,
@@ -113,15 +119,19 @@ TEST_F(StyledLabelTest, BasicWrapping) {
styled()->GetInsets().height() + 2 * label_preferred_size.height());
styled()->Layout();
ASSERT_EQ(2, styled()->child_count());
- EXPECT_EQ(3, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(3, styled()->child_at(0)->bounds().y());
- EXPECT_EQ(styled()->bounds().height() - 3,
- styled()->child_at(1)->bounds().bottom());
+ EXPECT_EQ(3, styled()->child_at(0)->x());
+ EXPECT_EQ(3, styled()->child_at(0)->y());
+ EXPECT_EQ(styled()->height() - 3, styled()->child_at(1)->bounds().bottom());
}
TEST_F(StyledLabelTest, CreateLinks) {
const std::string text("This is a test block of text.");
InitStyledLabel(text);
+
+ // Without links, there should be no focus border.
+ EXPECT_TRUE(styled()->GetInsets().empty());
+
+ // Now let's add some links.
styled()->AddStyleRange(gfx::Range(0, 1),
StyledLabel::RangeStyleInfo::CreateForLink());
styled()->AddStyleRange(gfx::Range(1, 2),
@@ -131,9 +141,13 @@ TEST_F(StyledLabelTest, CreateLinks) {
styled()->AddStyleRange(gfx::Range(12, 13),
StyledLabel::RangeStyleInfo::CreateForLink());
+ // Now there should be a focus border because there are non-empty Links.
+ EXPECT_FALSE(styled()->GetInsets().empty());
+
+ // Verify layout creates the right number of children.
styled()->SetBounds(0, 0, 1000, 1000);
styled()->Layout();
- ASSERT_EQ(7, styled()->child_count());
+ EXPECT_EQ(7, styled()->child_count());
}
TEST_F(StyledLabelTest, DontBreakLinks) {
@@ -153,13 +167,15 @@ TEST_F(StyledLabelTest, DontBreakLinks) {
styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
styled()->Layout();
ASSERT_EQ(2, styled()->child_count());
- EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
+ // The label has no focus border while the link (and thus overall styled
+ // label) does, so the label should be inset by the width of the focus border.
+ EXPECT_EQ(Label::kFocusBorderPadding, styled()->child_at(0)->x());
+ EXPECT_EQ(0, styled()->child_at(1)->x());
}
TEST_F(StyledLabelTest, StyledRangeWithDisabledLineWrapping) {
const std::string text("This is a test block of text, ");
- const std::string unbreakable_text("and this should not be breaked");
+ const std::string unbreakable_text("and this should not be broken");
InitStyledLabel(text + unbreakable_text);
StyledLabel::RangeStyleInfo style_info;
style_info.disable_line_wrapping = true;
@@ -177,8 +193,8 @@ TEST_F(StyledLabelTest, StyledRangeWithDisabledLineWrapping) {
styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
styled()->Layout();
ASSERT_EQ(2, styled()->child_count());
- EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
+ EXPECT_EQ(0, styled()->child_at(0)->x());
+ EXPECT_EQ(0, styled()->child_at(1)->x());
}
TEST_F(StyledLabelTest, StyledRangeUnderlined) {
@@ -197,8 +213,9 @@ TEST_F(StyledLabelTest, StyledRangeUnderlined) {
ASSERT_EQ(2, styled()->child_count());
ASSERT_EQ(std::string(Label::kViewClassName),
styled()->child_at(1)->GetClassName());
- EXPECT_EQ(gfx::Font::UNDERLINE,
- static_cast<Label*>(styled()->child_at(1))->font().GetStyle());
+ EXPECT_EQ(
+ gfx::Font::UNDERLINE,
+ static_cast<Label*>(styled()->child_at(1))->font_list().GetFontStyle());
}
TEST_F(StyledLabelTest, StyledRangeBold) {
@@ -215,7 +232,7 @@ TEST_F(StyledLabelTest, StyledRangeBold) {
// and normal style.
Label label(ASCIIToUTF16(bold_text));
const gfx::Size normal_label_size = label.GetPreferredSize();
- label.SetFont(label.font().DeriveFont(0, gfx::Font::BOLD));
+ label.SetFontList(label.font_list().DeriveWithStyle(gfx::Font::BOLD));
const gfx::Size bold_label_size = label.GetPreferredSize();
ASSERT_GE(bold_label_size.width(), normal_label_size.width());
@@ -230,7 +247,7 @@ TEST_F(StyledLabelTest, StyledRangeBold) {
StyledLabel unstyled(ASCIIToUTF16(bold_text), this);
unstyled.SetBounds(0, 0, styled_width, pref_height);
unstyled.Layout();
- ASSERT_EQ(1, unstyled.child_count());
+ EXPECT_EQ(1, unstyled.child_count());
styled()->SetBounds(0, 0, styled_width, pref_height);
styled()->Layout();
@@ -240,22 +257,25 @@ TEST_F(StyledLabelTest, StyledRangeBold) {
// The bold text should be broken up into two parts.
ASSERT_EQ(std::string(Label::kViewClassName),
styled()->child_at(0)->GetClassName());
- EXPECT_EQ(gfx::Font::BOLD,
- static_cast<Label*>(styled()->child_at(0))->font().GetStyle());
+ EXPECT_EQ(
+ gfx::Font::BOLD,
+ static_cast<Label*>(styled()->child_at(0))->font_list().GetFontStyle());
ASSERT_EQ(std::string(Label::kViewClassName),
styled()->child_at(1)->GetClassName());
- EXPECT_EQ(gfx::Font::BOLD,
- static_cast<Label*>(styled()->child_at(1))->font().GetStyle());
+ EXPECT_EQ(
+ gfx::Font::BOLD,
+ static_cast<Label*>(styled()->child_at(1))->font_list().GetFontStyle());
ASSERT_EQ(std::string(Label::kViewClassName),
styled()->child_at(2)->GetClassName());
- EXPECT_EQ(gfx::Font::NORMAL,
- static_cast<Label*>(styled()->child_at(2))->font().GetStyle());
+ EXPECT_EQ(
+ gfx::Font::NORMAL,
+ static_cast<Label*>(styled()->child_at(2))->font_list().GetFontStyle());
// The second bold part should start on a new line.
- EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
- EXPECT_EQ(styled()->child_at(1)->bounds().right() - 2,
- styled()->child_at(2)->bounds().x());
+ EXPECT_EQ(0, styled()->child_at(0)->x());
+ EXPECT_EQ(0, styled()->child_at(1)->x());
+ EXPECT_EQ(styled()->child_at(1)->bounds().right(),
+ styled()->child_at(2)->x());
}
TEST_F(StyledLabelTest, Color) {
@@ -274,16 +294,25 @@ TEST_F(StyledLabelTest, Color) {
text_red.size() + text_link.size()),
style_info_link);
+ styled()->SetBounds(0, 0, 1000, 1000);
+ styled()->Layout();
+
+ Widget* widget = new Widget();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ widget->Init(params);
+ View* container = new View();
+ widget->SetContentsView(container);
+ container->AddChildView(styled());
+
// Obtain the default text color for a label.
- Label label(ASCIIToUTF16(text));
- const SkColor kDefaultTextColor = label.enabled_color();
+ Label* label = new Label(ASCIIToUTF16(text));
+ container->AddChildView(label);
+ const SkColor kDefaultTextColor = label->enabled_color();
// Obtain the default text color for a link;
- Link link(ASCIIToUTF16(text_link));
- const SkColor kDefaultLinkColor = link.enabled_color();
-
- styled()->SetBounds(0, 0, 1000, 1000);
- styled()->Layout();
+ Link* link = new Link(ASCIIToUTF16(text_link));
+ container->AddChildView(link);
+ const SkColor kDefaultLinkColor = link->enabled_color();
EXPECT_EQ(SK_ColorRED,
static_cast<Label*>(styled()->child_at(0))->enabled_color());
@@ -291,23 +320,18 @@ TEST_F(StyledLabelTest, Color) {
static_cast<Label*>(styled()->child_at(1))->enabled_color());
EXPECT_EQ(kDefaultTextColor,
static_cast<Label*>(styled()->child_at(2))->enabled_color());
-}
-TEST_F(StyledLabelTest, ColorReadability) {
- const std::string text(
- "This is a block of text that needs color adjustment.");
- InitStyledLabel(text);
+ // Test adjusted color readability.
styled()->SetDisplayedOnBackgroundColor(SK_ColorBLACK);
-
- // Obtain the text color if it were a pure label.
- Label label(ASCIIToUTF16(text));
- label.SetBackgroundColor(SK_ColorBLACK);
-
- styled()->SetBounds(0, 0, 1000, 1000);
styled()->Layout();
+ label->SetBackgroundColor(SK_ColorBLACK);
- EXPECT_EQ(label.enabled_color(),
- static_cast<Label*>(styled()->child_at(0))->enabled_color());
+ const SkColor kAdjustedTextColor = label->enabled_color();
+ EXPECT_NE(kAdjustedTextColor, kDefaultTextColor);
+ EXPECT_EQ(kAdjustedTextColor,
+ static_cast<Label*>(styled()->child_at(2))->enabled_color());
+
+ widget->CloseNow();
}
TEST_F(StyledLabelTest, StyledRangeWithTooltip) {
@@ -343,15 +367,18 @@ TEST_F(StyledLabelTest, StyledRangeWithTooltip) {
EXPECT_EQ(label_preferred_size.width(), styled()->width());
ASSERT_EQ(5, styled()->child_count());
- EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(styled()->child_at(0)->bounds().right() - 2,
- styled()->child_at(1)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(2)->bounds().x());
- EXPECT_EQ(styled()->child_at(2)->bounds().right() - 2,
- styled()->child_at(3)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(4)->bounds().x());
-
- string16 tooltip;
+ // The labels have no focus border while the link (and thus overall styled
+ // label) does, so the labels should be inset by the width of the focus
+ // border.
+ EXPECT_EQ(Label::kFocusBorderPadding, styled()->child_at(0)->x());
+ EXPECT_EQ(styled()->child_at(0)->bounds().right(),
+ styled()->child_at(1)->x());
+ EXPECT_EQ(Label::kFocusBorderPadding, styled()->child_at(2)->x());
+ EXPECT_EQ(styled()->child_at(2)->bounds().right(),
+ styled()->child_at(3)->x());
+ EXPECT_EQ(0, styled()->child_at(4)->x());
+
+ base::string16 tooltip;
EXPECT_TRUE(
styled()->child_at(1)->GetTooltipText(gfx::Point(1, 1), &tooltip));
EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip);
@@ -360,11 +387,29 @@ TEST_F(StyledLabelTest, StyledRangeWithTooltip) {
EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip);
}
+TEST_F(StyledLabelTest, SetBaseFontList) {
+ const std::string text("This is a test block of text.");
+ InitStyledLabel(text);
+ std::string font_name("arial");
+ gfx::Font font(font_name, 30);
+ styled()->SetBaseFontList(gfx::FontList(font));
+ Label label(ASCIIToUTF16(text), gfx::FontList(font));
+
+ styled()->SetBounds(0,
+ 0,
+ label.GetPreferredSize().width(),
+ label.GetPreferredSize().height());
+
+ // Make sure we have the same sizing as a label.
+ EXPECT_EQ(label.GetPreferredSize().height(), styled()->height());
+ EXPECT_EQ(label.GetPreferredSize().width(), styled()->width());
+}
+
TEST_F(StyledLabelTest, HandleEmptyLayout) {
- const std::string text("This is a test block of text, ");
+ const std::string text("This is a test block of text.");
InitStyledLabel(text);
styled()->Layout();
- ASSERT_EQ(0, styled()->child_count());
+ EXPECT_EQ(0, styled()->child_count());
}
-} // namespace
+} // namespace views
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 3f2d5da96f5..3d181e0c8ce 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -5,10 +5,11 @@
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "base/logging.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
#include "ui/views/layout/layout_manager.h"
@@ -33,7 +34,7 @@ const char TabbedPane::kViewClassName[] = "TabbedPane";
// The tab view shown in the tab strip.
class Tab : public View {
public:
- Tab(TabbedPane* tabbed_pane, const string16& title, View* contents);
+ Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents);
virtual ~Tab();
View* contents() const { return contents_; }
@@ -46,7 +47,7 @@ class Tab : public View {
virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
private:
@@ -75,7 +76,7 @@ class TabStrip : public View {
virtual ~TabStrip();
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
@@ -85,12 +86,14 @@ class TabStrip : public View {
DISALLOW_COPY_AND_ASSIGN(TabStrip);
};
-Tab::Tab(TabbedPane* tabbed_pane, const string16& title, View* contents)
+Tab::Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents)
: tabbed_pane_(tabbed_pane),
- title_(new Label(title, gfx::Font().DeriveFont(0, gfx::Font::BOLD))),
+ title_(new Label(title,
+ ui::ResourceBundle::GetSharedInstance().GetFontList(
+ ui::ResourceBundle::BoldFont))),
tab_state_(TAB_ACTIVE),
contents_(contents) {
- // Calculate this now while the font is guaranteed to be bold.
+ // Calculate this now while the font list is guaranteed to be bold.
preferred_title_size_ = title_->GetPreferredSize();
SetState(TAB_INACTIVE);
@@ -136,7 +139,7 @@ void Tab::OnGestureEvent(ui::GestureEvent* event) {
event->SetHandled();
}
-gfx::Size Tab::GetPreferredSize() {
+gfx::Size Tab::GetPreferredSize() const {
gfx::Size size(preferred_title_size_);
size.Enlarge(21, 9);
const int kTabMinWidth = 54;
@@ -157,18 +160,19 @@ void Tab::SetState(TabState tab_state) {
return;
tab_state_ = tab_state;
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
switch (tab_state) {
case TAB_INACTIVE:
title_->SetEnabledColor(kTabTitleColor_Inactive);
- title_->SetFont(gfx::Font());
+ title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BaseFont));
break;
case TAB_ACTIVE:
title_->SetEnabledColor(kTabTitleColor_Active);
- title_->SetFont(gfx::Font().DeriveFont(0, gfx::Font::BOLD));
+ title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BoldFont));
break;
case TAB_HOVERED:
title_->SetEnabledColor(kTabTitleColor_Hovered);
- title_->SetFont(gfx::Font());
+ title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BaseFont));
break;
}
SchedulePaint();
@@ -178,7 +182,7 @@ TabStrip::TabStrip(TabbedPane* tabbed_pane) : tabbed_pane_(tabbed_pane) {}
TabStrip::~TabStrip() {}
-gfx::Size TabStrip::GetPreferredSize() {
+gfx::Size TabStrip::GetPreferredSize() const {
gfx::Size size;
for (int i = 0; i < child_count(); ++i) {
const gfx::Size child_size = child_at(i)->GetPreferredSize();
@@ -255,12 +259,12 @@ View* TabbedPane::GetSelectedTab() {
NULL : GetTabAt(selected_tab_index())->contents();
}
-void TabbedPane::AddTab(const string16& title, View* contents) {
+void TabbedPane::AddTab(const base::string16& title, View* contents) {
AddTabAtIndex(tab_strip_->child_count(), title, contents);
}
void TabbedPane::AddTabAtIndex(int index,
- const string16& title,
+ const base::string16& title,
View* contents) {
DCHECK(index >= 0 && index <= GetTabCount());
contents->SetVisible(false);
@@ -304,7 +308,7 @@ void TabbedPane::SelectTab(Tab* tab) {
SelectTabAt(index);
}
-gfx::Size TabbedPane::GetPreferredSize() {
+gfx::Size TabbedPane::GetPreferredSize() const {
gfx::Size size;
for (int i = 0; i < contents_->child_count(); ++i)
size.SetToMax(contents_->child_at(i)->GetPreferredSize());
@@ -360,12 +364,12 @@ void TabbedPane::OnFocus() {
View* selected_tab = GetSelectedTab();
if (selected_tab) {
selected_tab->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_FOCUS, true);
+ ui::AX_EVENT_FOCUS, true);
}
}
-void TabbedPane::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PAGETABLIST;
+void TabbedPane::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_TAB_LIST;
}
} // namespace views
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
index a837464a120..83c7fefb058 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
@@ -40,12 +40,12 @@ class VIEWS_EXPORT TabbedPane : public View {
// Adds a new tab at the end of this TabbedPane with the specified |title|.
// |contents| is the view displayed when the tab is selected and is owned by
// the TabbedPane.
- void AddTab(const string16& title, View* contents);
+ void AddTab(const base::string16& title, View* contents);
// Adds a new tab at |index| with |title|. |contents| is the view displayed
// when the tab is selected and is owned by the TabbedPane. If the tabbed pane
// is currently empty, the new tab is selected.
- void AddTabAtIndex(int index, const string16& title, View* contents);
+ void AddTabAtIndex(int index, const base::string16& title, View* contents);
// Selects the tab at |index|, which must be valid.
void SelectTabAt(int index);
@@ -54,7 +54,7 @@ class VIEWS_EXPORT TabbedPane : public View {
void SelectTab(Tab* tab);
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
private:
@@ -69,7 +69,7 @@ class VIEWS_EXPORT TabbedPane : public View {
const ViewHierarchyChangedDetails& details) OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
virtual void OnFocus() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// A listener notified when tab selection changes. Weak, not owned.
TabbedPaneListener* listener_;
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h
index d2607889ef1..83376f79df0 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h
@@ -5,11 +5,13 @@
#ifndef UI_VIEWS_CONTROLS_TABBED_PANE_TABBED_PANE_LISTENER_H_
#define UI_VIEWS_CONTROLS_TABBED_PANE_TABBED_PANE_LISTENER_H_
+#include "ui/views/views_export.h"
+
namespace views {
// An interface implemented by an object to let it know that a tabbed pane was
// selected by the user at the specified index.
-class TabbedPaneListener {
+class VIEWS_EXPORT TabbedPaneListener {
public:
// Called when the tab at |index| is selected by the user.
virtual void TabSelectedAt(int index) = 0;
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
index f887a8d2ff4..f81c2a870cb 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -9,6 +9,8 @@
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/test/views_test_base.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace {
@@ -20,7 +22,7 @@ class FixedSizeView : public View {
: size_(size) {}
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return size_;
}
diff --git a/chromium/ui/views/controls/table/table_grouper.h b/chromium/ui/views/controls/table/table_grouper.h
index d6659ac1956..ce100e4c98a 100644
--- a/chromium/ui/views/controls/table/table_grouper.h
+++ b/chromium/ui/views/controls/table/table_grouper.h
@@ -5,9 +5,11 @@
#ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_GROUPER_H_
#define UI_VIEWS_CONTROLS_TABLE_TABLE_GROUPER_H_
+#include "ui/views/views_export.h"
+
namespace views {
-struct GroupRange {
+struct VIEWS_EXPORT GroupRange {
int start;
int length;
};
@@ -15,7 +17,7 @@ struct GroupRange {
// TableGrouper is used by TableView to group a set of rows and treat them
// as one. Rows that fall in the same group are selected together and sorted
// together.
-class TableGrouper {
+class VIEWS_EXPORT TableGrouper {
public:
virtual void GetGroupRange(int model_index, GroupRange* range) = 0;
diff --git a/chromium/ui/views/controls/table/table_header.cc b/chromium/ui/views/controls/table/table_header.cc
index 16d28e3e010..a9d730f958e 100644
--- a/chromium/ui/views/controls/table/table_header.cc
+++ b/chromium/ui/views/controls/table/table_header.cc
@@ -5,15 +5,14 @@
#include "ui/views/controls/table/table_header.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/text_utils.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/controls/table/table_utils.h"
#include "ui/views/controls/table/table_view.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+#include "ui/views/native_cursor.h"
namespace views {
@@ -38,15 +37,6 @@ const SkColor kSeparatorColor = SkColorSetRGB(0xAA, 0xAA, 0xAA);
// Size of the sort indicator (doesn't include padding).
const int kSortIndicatorSize = 8;
-gfx::NativeCursor GetResizeCursor() {
-#if defined(USE_AURA)
- return ui::kCursorColumnResize;
-#elif defined(OS_WIN)
- static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_SIZEWE);
- return g_hand_cursor;
-#endif
-}
-
} // namespace
// static
@@ -95,7 +85,8 @@ void TableHeader::OnPaint(gfx::Canvas* canvas) {
if (width <= 0)
continue;
- const int title_width = font_.GetStringWidth(columns[i].column.title);
+ const int title_width =
+ gfx::GetStringWidth(columns[i].column.title, font_list_);
const bool paint_sort_indicator =
(columns[i].column.id == sorted_column_id &&
title_width + kSortIndicatorWidth <= width);
@@ -105,10 +96,10 @@ void TableHeader::OnPaint(gfx::Canvas* canvas) {
width -= kSortIndicatorWidth;
}
- canvas->DrawStringInt(
- columns[i].column.title, font_, kTextColor,
- GetMirroredXWithWidthInView(x, width), kVerticalPadding, width,
- height() - kVerticalPadding * 2,
+ canvas->DrawStringRectWithFlags(
+ columns[i].column.title, font_list_, kTextColor,
+ gfx::Rect(GetMirroredXWithWidthInView(x, width), kVerticalPadding,
+ width, height() - kVerticalPadding * 2),
TableColumnAlignmentToCanvasAlignment(columns[i].column.alignment));
if (paint_sort_indicator) {
@@ -168,13 +159,13 @@ void TableHeader::OnPaint(gfx::Canvas* canvas) {
}
}
-gfx::Size TableHeader::GetPreferredSize() {
- return gfx::Size(1, kVerticalPadding * 2 + font_.GetHeight());
+gfx::Size TableHeader::GetPreferredSize() const {
+ return gfx::Size(1, kVerticalPadding * 2 + font_list_.GetHeight());
}
gfx::NativeCursor TableHeader::GetCursor(const ui::MouseEvent& event) {
return GetResizeColumn(GetMirroredXInView(event.x())) != -1 ?
- GetResizeCursor() : View::GetCursor(event);
+ GetNativeColumnResizeCursor() : View::GetCursor(event);
}
bool TableHeader::OnMousePressed(const ui::MouseEvent& event) {
diff --git a/chromium/ui/views/controls/table/table_header.h b/chromium/ui/views/controls/table/table_header.h
index 2aa280d2d92..a595de949c6 100644
--- a/chromium/ui/views/controls/table/table_header.h
+++ b/chromium/ui/views/controls/table/table_header.h
@@ -5,7 +5,7 @@
#ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_HEADER_H_
#define UI_VIEWS_CONTROLS_TABLE_TABLE_HEADER_H_
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
@@ -25,12 +25,12 @@ class VIEWS_EXPORT TableHeader : public views::View {
explicit TableHeader(TableView* table);
virtual ~TableHeader();
- const gfx::Font& font() const { return font_; }
+ const gfx::FontList& font_list() const { return font_list_; }
// views::View overrides.
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
@@ -70,7 +70,7 @@ class VIEWS_EXPORT TableHeader : public views::View {
bool is_resizing() const { return resize_details_.get() != NULL; }
- const gfx::Font font_;
+ const gfx::FontList font_list_;
TableView* table_;
diff --git a/chromium/ui/views/controls/table/table_utils.cc b/chromium/ui/views/controls/table/table_utils.cc
index 1e730d0a938..393c22dbc6f 100644
--- a/chromium/ui/views/controls/table/table_utils.cc
+++ b/chromium/ui/views/controls/table/table_utils.cc
@@ -6,26 +6,28 @@
#include "base/logging.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/text_utils.h"
#include "ui/views/controls/table/table_view.h"
namespace views {
const int kUnspecifiedColumnWidth = 90;
-int WidthForContent(const gfx::Font& header_font,
- const gfx::Font& content_font,
+int WidthForContent(const gfx::FontList& header_font_list,
+ const gfx::FontList& content_font_list,
int padding,
int header_padding,
const ui::TableColumn& column,
ui::TableModel* model) {
int width = header_padding;
if (!column.title.empty())
- width = header_font.GetStringWidth(column.title) + header_padding;
+ width = gfx::GetStringWidth(column.title, header_font_list) +
+ header_padding;
for (int i = 0, row_count = model->RowCount(); i < row_count; ++i) {
const int cell_width =
- content_font.GetStringWidth(model->GetText(i, column.id));
+ gfx::GetStringWidth(model->GetText(i, column.id), content_font_list);
width = std::max(width, cell_width);
}
return width + padding;
@@ -34,8 +36,8 @@ int WidthForContent(const gfx::Font& header_font,
std::vector<int> CalculateTableColumnSizes(
int width,
int first_column_padding,
- const gfx::Font& header_font,
- const gfx::Font& content_font,
+ const gfx::FontList& header_font_list,
+ const gfx::FontList& content_font_list,
int padding,
int header_padding,
const std::vector<ui::TableColumn>& columns,
@@ -49,11 +51,12 @@ std::vector<int> CalculateTableColumnSizes(
if (column.percent > 0) {
total_percent += column.percent;
// Make sure there is at least enough room for the header.
- content_widths[i] = header_font.GetStringWidth(column.title) + padding +
- header_padding;
+ content_widths[i] = gfx::GetStringWidth(column.title, header_font_list)
+ + padding + header_padding;
} else {
- content_widths[i] = WidthForContent(header_font, content_font, padding,
- header_padding, column, model);
+ content_widths[i] = WidthForContent(header_font_list, content_font_list,
+ padding, header_padding, column,
+ model);
if (i == 0)
content_widths[i] += first_column_padding;
}
diff --git a/chromium/ui/views/controls/table/table_utils.h b/chromium/ui/views/controls/table/table_utils.h
index 3c5d4c78175..ec387102e69 100644
--- a/chromium/ui/views/controls/table/table_utils.h
+++ b/chromium/ui/views/controls/table/table_utils.h
@@ -11,7 +11,7 @@
#include "ui/views/views_export.h"
namespace gfx {
-class Font;
+class FontList;
}
namespace views {
@@ -23,23 +23,23 @@ VIEWS_EXPORT extern const int kUnspecifiedColumnWidth;
// Returns the width needed to display the contents of the specified column.
// This is used internally by CalculateTableColumnSizes() and generally not
// useful by itself. |header_padding| is padding added to the header.
-VIEWS_EXPORT int WidthForContent(const gfx::Font& header_font,
- const gfx::Font& content_font,
+VIEWS_EXPORT int WidthForContent(const gfx::FontList& header_font_list,
+ const gfx::FontList& content_font_list,
int padding,
int header_padding,
const ui::TableColumn& column,
ui::TableModel* model);
// Determines the width for each of the specified columns. |width| is the width
-// to fit the columns into. |header_font| the font used to draw the header and
-// |content_font| the header used to draw the content. |padding| is extra
-// horizontal spaced added to each cell, and |header_padding| added to the
-// width needed for the header.
+// to fit the columns into. |header_font_list| the font list used to draw the
+// header and |content_font_list| the header used to draw the content. |padding|
+// is extra horizontal spaced added to each cell, and |header_padding| added to
+// the width needed for the header.
VIEWS_EXPORT std::vector<int> CalculateTableColumnSizes(
int width,
int first_column_padding,
- const gfx::Font& header_font,
- const gfx::Font& content_font,
+ const gfx::FontList& header_font_list,
+ const gfx::FontList& content_font_list,
int padding,
int header_padding,
const std::vector<ui::TableColumn>& columns,
diff --git a/chromium/ui/views/controls/table/table_utils_unittest.cc b/chromium/ui/views/controls/table/table_utils_unittest.cc
index e6c6369d0b8..98b1fd2f786 100644
--- a/chromium/ui/views/controls/table/table_utils_unittest.cc
+++ b/chromium/ui/views/controls/table/table_utils_unittest.cc
@@ -6,7 +6,7 @@
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/controls/table/test_table_model.h"
using ui::TableColumn;
@@ -40,17 +40,19 @@ TEST(TableUtilsTest, SetWidthHonored) {
std::vector<TableColumn> columns;
columns.push_back(CreateTableColumnWithWidth(20));
columns.push_back(CreateTableColumnWithWidth(30));
- gfx::Font font;
- std::vector<int> result(
- CalculateTableColumnSizes(100, 0, font, font, 0, 0, columns, &model));
+ gfx::FontList font_list;
+ std::vector<int> result(CalculateTableColumnSizes(
+ 100, 0, font_list, font_list, 0, 0, columns, &model));
EXPECT_EQ("20,30", IntVectorToString(result));
// Same with some padding, it should be ignored.
- result = CalculateTableColumnSizes(100, 0, font, font, 2, 0, columns, &model);
+ result = CalculateTableColumnSizes(
+ 100, 0, font_list, font_list, 2, 0, columns, &model);
EXPECT_EQ("20,30", IntVectorToString(result));
// Same with not enough space, it shouldn't matter.
- result = CalculateTableColumnSizes(10, 0, font, font, 2, 0, columns, &model);
+ result = CalculateTableColumnSizes(
+ 10, 0, font_list, font_list, 2, 0, columns, &model);
EXPECT_EQ("20,30", IntVectorToString(result));
}
@@ -61,11 +63,12 @@ TEST(TableUtilsTest, LastColumnGetsAllSpace) {
std::vector<TableColumn> columns;
columns.push_back(ui::TableColumn());
columns.push_back(ui::TableColumn());
- gfx::Font font;
- std::vector<int> result(
- CalculateTableColumnSizes(500, 0, font, font, 0, 0, columns, &model));
+ gfx::FontList font_list;
+ std::vector<int> result(CalculateTableColumnSizes(
+ 500, 0, font_list, font_list, 0, 0, columns, &model));
EXPECT_NE(0, result[0]);
- EXPECT_GE(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ EXPECT_GE(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(500, result[0] + result[1]);
}
@@ -77,38 +80,45 @@ TEST(TableUtilsTest, SingleResizableColumn) {
columns.push_back(ui::TableColumn());
columns.push_back(ui::TableColumn());
columns[2].percent = 1.0f;
- gfx::Font font;
- std::vector<int> result(
- CalculateTableColumnSizes(500, 0, font, font, 0, 0, columns, &model));
- EXPECT_EQ(result[0], WidthForContent(font, font, 0, 0, columns[0], &model));
- EXPECT_EQ(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ gfx::FontList font_list;
+ std::vector<int> result(CalculateTableColumnSizes(
+ 500, 0, font_list, font_list, 0, 0, columns, &model));
+ EXPECT_EQ(result[0],
+ WidthForContent(font_list, font_list, 0, 0, columns[0], &model));
+ EXPECT_EQ(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(500 - result[0] - result[1], result[2]);
// The same with a slightly larger width passed in.
- result =
- CalculateTableColumnSizes(1000, 0, font, font, 0, 0, columns, &model);
- EXPECT_EQ(result[0], WidthForContent(font, font, 0, 0, columns[0], &model));
- EXPECT_EQ(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ result = CalculateTableColumnSizes(
+ 1000, 0, font_list, font_list, 0, 0, columns, &model);
+ EXPECT_EQ(result[0],
+ WidthForContent(font_list, font_list, 0, 0, columns[0], &model));
+ EXPECT_EQ(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(1000 - result[0] - result[1], result[2]);
// Verify padding for the first column is honored.
- result =
- CalculateTableColumnSizes(1000, 10, font, font, 0, 0, columns, &model);
+ result = CalculateTableColumnSizes(
+ 1000, 10, font_list, font_list, 0, 0, columns, &model);
EXPECT_EQ(result[0],
- WidthForContent(font, font, 0, 0, columns[0], &model) + 10);
- EXPECT_EQ(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ WidthForContent(font_list, font_list, 0, 0, columns[0], &model)
+ + 10);
+ EXPECT_EQ(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(1000 - result[0] - result[1], result[2]);
// Just enough space to show the first two columns. Should force last column
// to min size.
- result =
- CalculateTableColumnSizes(1000, 0, font, font, 0, 0, columns, &model);
- result = CalculateTableColumnSizes(result[0] + result[1], 0, font, font, 0, 0,
- columns, &model);
- EXPECT_EQ(result[0], WidthForContent(font, font, 0, 0, columns[0], &model));
- EXPECT_EQ(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ result = CalculateTableColumnSizes(
+ 1000, 0, font_list, font_list, 0, 0, columns, &model);
+ result = CalculateTableColumnSizes(
+ result[0] + result[1], 0, font_list, font_list, 0, 0, columns, &model);
+ EXPECT_EQ(result[0],
+ WidthForContent(font_list, font_list, 0, 0, columns[0], &model));
+ EXPECT_EQ(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(kUnspecifiedColumnWidth, result[2]);
}
} // namespace views
-
diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc
index 8a27a1f7a91..e5120d49295 100644
--- a/chromium/ui/views/controls/table/table_view.cc
+++ b/chromium/ui/views/controls/table/table_view.cc
@@ -13,6 +13,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/text_utils.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/table/table_grouper.h"
@@ -124,7 +125,7 @@ TableView::TableView(ui::TableModel* model,
table_type_(table_type),
single_selection_(single_selection),
table_view_observer_(NULL),
- row_height_(font_.GetHeight() + kTextVerticalPadding * 2),
+ row_height_(font_list_.GetHeight() + kTextVerticalPadding * 2),
last_parent_width_(0),
layout_width_(0),
grouper_(NULL),
@@ -317,7 +318,7 @@ void TableView::Layout() {
SetBounds(x(), y(), width, height);
}
-gfx::Size TableView::GetPreferredSize() {
+gfx::Size TableView::GetPreferredSize() const {
int width = 50;
if (header_ && !visible_columns_.empty())
width = visible_columns_.back().x + visible_columns_.back().width;
@@ -404,7 +405,7 @@ void TableView::OnGestureEvent(ui::GestureEvent* event) {
}
bool TableView::GetTooltipText(const gfx::Point& p,
- string16* tooltip) const {
+ base::string16* tooltip) const {
return GetTooltipImpl(p, tooltip, NULL);
}
@@ -522,14 +523,14 @@ void TableView::OnPaint(gfx::Canvas* canvas) {
text_x += kImageSize + kTextHorizontalPadding;
}
if (text_x < cell_bounds.right() - kTextHorizontalPadding) {
- canvas->DrawStringInt(
- model_->GetText(model_index, visible_columns_[j].column.id), font_,
- is_selected ? selected_fg_color : fg_color,
- GetMirroredXWithWidthInView(text_x, cell_bounds.right() - text_x -
- kTextHorizontalPadding),
- cell_bounds.y() + kTextVerticalPadding,
- cell_bounds.right() - text_x,
- cell_bounds.height() - kTextVerticalPadding * 2,
+ canvas->DrawStringRectWithFlags(
+ model_->GetText(model_index, visible_columns_[j].column.id),
+ font_list_, is_selected ? selected_fg_color : fg_color,
+ gfx::Rect(GetMirroredXWithWidthInView(
+ text_x, cell_bounds.right() - text_x - kTextHorizontalPadding),
+ cell_bounds.y() + kTextVerticalPadding,
+ cell_bounds.right() - text_x,
+ cell_bounds.height() - kTextVerticalPadding * 2),
TableColumnAlignmentToCanvasAlignment(
visible_columns_[j].column.alignment));
}
@@ -684,7 +685,7 @@ void TableView::UpdateVisibleColumnSizes() {
first_column_padding += kGroupingIndicatorSize + kTextHorizontalPadding;
std::vector<int> sizes = views::CalculateTableColumnSizes(
- layout_width_, first_column_padding, header_->font(), font_,
+ layout_width_, first_column_padding, header_->font_list(), font_list_,
std::max(kTextHorizontalPadding, TableHeader::kHorizontalPadding) * 2,
TableHeader::kSortIndicatorWidth, columns, model_);
DCHECK_EQ(visible_columns_.size(), sizes.size());
@@ -871,7 +872,7 @@ GroupRange TableView::GetGroupRange(int model_index) const {
}
bool TableView::GetTooltipImpl(const gfx::Point& location,
- string16* tooltip,
+ base::string16* tooltip,
gfx::Point* tooltip_origin) const {
const int row = location.y() / row_height_;
if (row < 0 || row >= RowCount() || visible_columns_.empty())
@@ -883,7 +884,7 @@ bool TableView::GetTooltipImpl(const gfx::Point& location,
x > (visible_columns_[column].x + visible_columns_[column].width))
return false;
- const string16 text(model_->GetText(ViewToModel(row),
+ const base::string16 text(model_->GetText(ViewToModel(row),
visible_columns_[column].column.id));
if (text.empty())
return false;
@@ -892,7 +893,7 @@ bool TableView::GetTooltipImpl(const gfx::Point& location,
AdjustCellBoundsForText(column, &cell_bounds);
const int right = std::min(GetVisibleBounds().right(), cell_bounds.right());
if (right > cell_bounds.x() &&
- font_.GetStringWidth(text) <= (right - cell_bounds.x()))
+ gfx::GetStringWidth(text, font_list_) <= (right - cell_bounds.x()))
return false;
if (tooltip)
diff --git a/chromium/ui/views/controls/table/table_view.h b/chromium/ui/views/controls/table/table_view.h
index c2a94724a52..96268067c6b 100644
--- a/chromium/ui/views/controls/table/table_view.h
+++ b/chromium/ui/views/controls/table/table_view.h
@@ -11,7 +11,7 @@
#include "ui/base/models/list_selection_model.h"
#include "ui/base/models/table_model.h"
#include "ui/base/models/table_model_observer.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
@@ -166,12 +166,12 @@ class VIEWS_EXPORT TableView
// View overrides:
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
virtual bool GetTooltipTextOrigin(const gfx::Point& p,
gfx::Point* loc) const OVERRIDE;
@@ -291,7 +291,7 @@ class VIEWS_EXPORT TableView
// sets |tooltip| and/or |tooltip_origin| as appropriate, each of which may be
// NULL.
bool GetTooltipImpl(const gfx::Point& location,
- string16* tooltip,
+ base::string16* tooltip,
gfx::Point* tooltip_origin) const;
ui::TableModel* model_;
@@ -316,7 +316,7 @@ class VIEWS_EXPORT TableView
// The selection, in terms of the model.
ui::ListSelectionModel selection_model_;
- gfx::Font font_;
+ gfx::FontList font_list_;
int row_height_;
diff --git a/chromium/ui/views/controls/table/table_view_observer.h b/chromium/ui/views/controls/table/table_view_observer.h
index 44400eee1c7..9cea2603c50 100644
--- a/chromium/ui/views/controls/table/table_view_observer.h
+++ b/chromium/ui/views/controls/table/table_view_observer.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_OBSERVER_H_
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/views_export.h"
namespace views {
@@ -13,7 +14,7 @@ class TableView;
class TableView2;
// TableViewObserver is notified about the TableView selection.
-class TableViewObserver {
+class VIEWS_EXPORT TableViewObserver {
public:
virtual ~TableViewObserver() {}
diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc
index 4d89f3272b3..1d59358d31e 100644
--- a/chromium/ui/views/controls/table/table_view_unittest.cc
+++ b/chromium/ui/views/controls/table/table_view_unittest.cc
@@ -67,7 +67,7 @@ class TestTableModel2 : public ui::TableModel {
// ui::TableModel:
virtual int RowCount() OVERRIDE;
- virtual string16 GetText(int row, int column_id) OVERRIDE;
+ virtual base::string16 GetText(int row, int column_id) OVERRIDE;
virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
virtual int CompareValues(int row1, int row2, int column_id) OVERRIDE;
@@ -115,7 +115,7 @@ int TestTableModel2::RowCount() {
return static_cast<int>(rows_.size());
}
-string16 TestTableModel2::GetText(int row, int column_id) {
+base::string16 TestTableModel2::GetText(int row, int column_id) {
return base::IntToString16(rows_[row][column_id]);
}
@@ -175,9 +175,9 @@ class TableViewTest : public testing::Test {
virtual void SetUp() OVERRIDE {
model_.reset(new TestTableModel2);
std::vector<ui::TableColumn> columns(2);
- columns[0].title = ASCIIToUTF16("Title Column 0");
+ columns[0].title = base::ASCIIToUTF16("Title Column 0");
columns[0].sortable = true;
- columns[1].title = ASCIIToUTF16("Title Column 1");
+ columns[1].title = base::ASCIIToUTF16("Title Column 1");
columns[1].id = 1;
columns[1].sortable = true;
table_ = new TestTableView(model_.get(), columns);
@@ -191,7 +191,8 @@ class TableViewTest : public testing::Test {
const int y = row * table_->row_height();
const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(0, y),
gfx::Point(0, y),
- ui::EF_LEFT_MOUSE_BUTTON | flags);
+ ui::EF_LEFT_MOUSE_BUTTON | flags,
+ ui::EF_LEFT_MOUSE_BUTTON);
table_->OnMousePressed(pressed);
}
@@ -289,10 +290,12 @@ TEST_F(TableViewTest, Resize) {
EXPECT_NE(0, x);
// Drag the mouse 1 pixel to the left.
const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(x, 0),
- gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
helper_->header()->OnMousePressed(pressed);
const ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, gfx::Point(x - 1, 0),
- gfx::Point(x - 1, 0), ui::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point(x - 1, 0), ui::EF_LEFT_MOUSE_BUTTON,
+ 0);
helper_->header()->OnMouseDragged(dragged);
// This should shrink the first column and pull the second column in.
@@ -378,11 +381,13 @@ TEST_F(TableViewTest, SortOnMouse) {
EXPECT_NE(0, x);
// Press and release the mouse.
const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(x, 0),
- gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
// The header must return true, else it won't normally get the release.
EXPECT_TRUE(helper_->header()->OnMousePressed(pressed));
const ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(x, 0),
- gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
helper_->header()->OnMouseReleased(release);
ASSERT_EQ(1u, table_->sort_descriptors().size());
diff --git a/chromium/ui/views/controls/table/test_table_model.cc b/chromium/ui/views/controls/table/test_table_model.cc
index c855aa163ec..6cac56cff3d 100644
--- a/chromium/ui/views/controls/table/test_table_model.cc
+++ b/chromium/ui/views/controls/table/test_table_model.cc
@@ -22,9 +22,9 @@ int TestTableModel::RowCount() {
return row_count_;
}
-string16 TestTableModel::GetText(int row, int column_id) {
- return ASCIIToUTF16(base::IntToString(row) + "x" +
- base::IntToString(column_id));
+base::string16 TestTableModel::GetText(int row, int column_id) {
+ return base::ASCIIToUTF16(base::IntToString(row) + "x" +
+ base::IntToString(column_id));
}
gfx::ImageSkia TestTableModel::GetIcon(int row) {
diff --git a/chromium/ui/views/controls/table/test_table_model.h b/chromium/ui/views/controls/table/test_table_model.h
index d093102fbe9..8338aae78a5 100644
--- a/chromium/ui/views/controls/table/test_table_model.h
+++ b/chromium/ui/views/controls/table/test_table_model.h
@@ -15,7 +15,7 @@ class TestTableModel : public ui::TableModel {
// ui::TableModel overrides:
virtual int RowCount() OVERRIDE;
- virtual string16 GetText(int row, int column_id) OVERRIDE;
+ virtual base::string16 GetText(int row, int column_id) OVERRIDE;
virtual gfx::ImageSkia GetIcon(int row) OVERRIDE;
virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
diff --git a/chromium/ui/views/controls/textfield/native_textfield_views.cc b/chromium/ui/views/controls/textfield/native_textfield_views.cc
deleted file mode 100644
index f8fc36217d2..00000000000
--- a/chromium/ui/views/controls/textfield/native_textfield_views.cc
+++ /dev/null
@@ -1,1545 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/textfield/native_textfield_views.h"
-
-#include <algorithm>
-#include <set>
-
-#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/i18n/case_conversion.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "grit/ui_strings.h"
-#include "third_party/icu/source/common/unicode/uchar.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/drag_utils.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/ui_base_switches_util.h"
-#include "ui/compositor/layer.h"
-#include "ui/events/event.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/range/range.h"
-#include "ui/gfx/render_text.h"
-#include "ui/gfx/text_constants.h"
-#include "ui/native_theme/native_theme.h"
-#include "ui/views/background.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/focusable_border.h"
-#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/menu_model_adapter.h"
-#include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/controls/textfield/textfield_views_model.h"
-#include "ui/views/drag_utils.h"
-#include "ui/views/ime/input_method.h"
-#include "ui/views/metrics.h"
-#include "ui/views/widget/widget.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
-
-#if defined(OS_WIN) && defined(USE_AURA)
-#include "base/win/win_util.h"
-#endif
-
-namespace {
-
-void ConvertRectToScreen(const views::View* src, gfx::Rect* r) {
- DCHECK(src);
-
- gfx::Point new_origin = r->origin();
- views::View::ConvertPointToScreen(src, &new_origin);
- r->set_origin(new_origin);
-}
-
-} // namespace
-
-namespace views {
-
-const char NativeTextfieldViews::kViewClassName[] =
- "views/NativeTextfieldViews";
-
-NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
- : textfield_(parent),
- model_(new TextfieldViewsModel(this)),
- text_border_(new FocusableBorder()),
- is_cursor_visible_(false),
- is_drop_cursor_visible_(false),
- skip_input_method_cancel_composition_(false),
- initiating_drag_(false),
- cursor_timer_(this),
- aggregated_clicks_(0) {
- set_border(text_border_);
- GetRenderText()->SetFontList(textfield_->font_list());
- UpdateColorsFromTheme(GetNativeTheme());
- set_context_menu_controller(this);
- parent->set_context_menu_controller(this);
- set_drag_controller(this);
-}
-
-NativeTextfieldViews::~NativeTextfieldViews() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, View overrides:
-
-bool NativeTextfieldViews::OnMousePressed(const ui::MouseEvent& event) {
- OnBeforeUserAction();
- TrackMouseClicks(event);
-
- TextfieldController* controller = textfield_->GetController();
- if (!(controller && controller->HandleMouseEvent(textfield_, event)) &&
- !textfield_->OnMousePressed(event)) {
- HandleMousePressEvent(event);
- }
-
- OnAfterUserAction();
- touch_selection_controller_.reset();
- return true;
-}
-
-bool NativeTextfieldViews::ExceededDragThresholdFromLastClickLocation(
- const ui::MouseEvent& event) {
- return ExceededDragThreshold(event.location() - last_click_location_);
-}
-
-bool NativeTextfieldViews::OnMouseDragged(const ui::MouseEvent& event) {
- // Don't adjust the cursor on a potential drag and drop, or if the mouse
- // movement from the last mouse click does not exceed the drag threshold.
- if (initiating_drag_ || !ExceededDragThresholdFromLastClickLocation(event) ||
- !event.IsOnlyLeftMouseButton()) {
- return true;
- }
-
- OnBeforeUserAction();
- // TODO: Remove once NativeTextfield implementations are consolidated to
- // Textfield.
- if (!textfield_->OnMouseDragged(event)) {
- MoveCursorTo(event.location(), true);
- if (aggregated_clicks_ == 1) {
- model_->SelectWord();
- // Expand the selection so the initially selected word remains selected.
- gfx::Range selection = GetRenderText()->selection();
- const size_t min = std::min(selection.GetMin(),
- double_click_word_.GetMin());
- const size_t max = std::max(selection.GetMax(),
- double_click_word_.GetMax());
- const bool reversed = selection.is_reversed();
- selection.set_start(reversed ? max : min);
- selection.set_end(reversed ? min : max);
- model_->SelectRange(selection);
- }
- SchedulePaint();
- }
- OnAfterUserAction();
- return true;
-}
-
-void NativeTextfieldViews::OnMouseReleased(const ui::MouseEvent& event) {
- OnBeforeUserAction();
- // TODO: Remove once NativeTextfield implementations are consolidated to
- // Textfield.
- textfield_->OnMouseReleased(event);
- // Cancel suspected drag initiations, the user was clicking in the selection.
- if (initiating_drag_ && MoveCursorTo(event.location(), false))
- SchedulePaint();
- initiating_drag_ = false;
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::OnGestureEvent(ui::GestureEvent* event) {
- textfield_->OnGestureEvent(event);
- if (event->handled())
- return;
-
- switch (event->type()) {
- case ui::ET_GESTURE_TAP_DOWN:
- OnBeforeUserAction();
- textfield_->RequestFocus();
- // We don't deselect if the point is in the selection
- // because TAP_DOWN may turn into a LONG_PRESS.
- if (!GetRenderText()->IsPointInSelection(event->location()) &&
- MoveCursorTo(event->location(), false))
- SchedulePaint();
- OnAfterUserAction();
- event->SetHandled();
- break;
- case ui::ET_GESTURE_SCROLL_UPDATE:
- OnBeforeUserAction();
- if (MoveCursorTo(event->location(), true))
- SchedulePaint();
- OnAfterUserAction();
- event->SetHandled();
- break;
- case ui::ET_GESTURE_SCROLL_END:
- case ui::ET_SCROLL_FLING_START:
- CreateTouchSelectionControllerAndNotifyIt();
- event->SetHandled();
- break;
- case ui::ET_GESTURE_TAP:
- if (event->details().tap_count() == 1) {
- CreateTouchSelectionControllerAndNotifyIt();
- } else {
- OnBeforeUserAction();
- SelectAll(false);
- OnAfterUserAction();
- event->SetHandled();
- }
- break;
- case ui::ET_GESTURE_LONG_PRESS:
- // If long press happens outside selection, select word and show context
- // menu (If touch selection is enabled, context menu is shown by the
- // |touch_selection_controller_|, hence we mark the event handled.
- // Otherwise, the regular context menu will be shown by views).
- // If long press happens in selected text and touch drag drop is enabled,
- // we will turn off touch selection (if one exists) and let views do drag
- // drop.
- if (!GetRenderText()->IsPointInSelection(event->location())) {
- OnBeforeUserAction();
- model_->SelectWord();
- touch_selection_controller_.reset(
- ui::TouchSelectionController::create(this));
- OnCaretBoundsChanged();
- SchedulePaint();
- OnAfterUserAction();
- if (touch_selection_controller_.get())
- event->SetHandled();
- } else if (switches::IsTouchDragDropEnabled()) {
- initiating_drag_ = true;
- touch_selection_controller_.reset();
- } else {
- if (!touch_selection_controller_.get())
- CreateTouchSelectionControllerAndNotifyIt();
- if (touch_selection_controller_.get())
- event->SetHandled();
- }
- return;
- case ui::ET_GESTURE_LONG_TAP:
- if (!touch_selection_controller_.get())
- CreateTouchSelectionControllerAndNotifyIt();
-
- // If touch selection is enabled, the context menu on long tap will be
- // shown by the |touch_selection_controller_|, hence we mark the event
- // handled so views does not try to show context menu on it.
- if (touch_selection_controller_.get())
- event->SetHandled();
- break;
- default:
- View::OnGestureEvent(event);
- return;
- }
- PlatformGestureEventHandling(event);
-}
-
-bool NativeTextfieldViews::OnKeyPressed(const ui::KeyEvent& event) {
- // OnKeyPressed/OnKeyReleased/OnFocus/OnBlur will never be invoked on
- // NativeTextfieldViews as it will never gain focus.
- NOTREACHED();
- return false;
-}
-
-bool NativeTextfieldViews::OnKeyReleased(const ui::KeyEvent& event) {
- NOTREACHED();
- return false;
-}
-
-bool NativeTextfieldViews::GetDropFormats(
- int* formats,
- std::set<OSExchangeData::CustomFormat>* custom_formats) {
- if (!textfield_->enabled() || textfield_->read_only())
- return false;
- // TODO(msw): Can we support URL, FILENAME, etc.?
- *formats = ui::OSExchangeData::STRING;
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->AppendDropFormats(formats, custom_formats);
- return true;
-}
-
-bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) {
- int formats;
- std::set<OSExchangeData::CustomFormat> custom_formats;
- GetDropFormats(&formats, &custom_formats);
- return textfield_->enabled() && !textfield_->read_only() &&
- data.HasAnyFormat(formats, custom_formats);
-}
-
-int NativeTextfieldViews::OnDragUpdated(const ui::DropTargetEvent& event) {
- DCHECK(CanDrop(event.data()));
-
- const gfx::Range& selection = GetRenderText()->selection();
- drop_cursor_position_ = GetRenderText()->FindCursorPosition(event.location());
- bool in_selection = !selection.is_empty() &&
- selection.Contains(gfx::Range(drop_cursor_position_.caret_pos()));
- is_drop_cursor_visible_ = !in_selection;
- // TODO(msw): Pan over text when the user drags to the visible text edge.
- OnCaretBoundsChanged();
- SchedulePaint();
-
- if (initiating_drag_) {
- if (in_selection)
- return ui::DragDropTypes::DRAG_NONE;
- return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
- ui::DragDropTypes::DRAG_MOVE;
- }
- return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
-}
-
-void NativeTextfieldViews::OnDragExited() {
- is_drop_cursor_visible_ = false;
- SchedulePaint();
-}
-
-int NativeTextfieldViews::OnPerformDrop(const ui::DropTargetEvent& event) {
- DCHECK(CanDrop(event.data()));
-
- is_drop_cursor_visible_ = false;
-
- TextfieldController* controller = textfield_->GetController();
- if (controller) {
- int drag_operation = controller->OnDrop(event.data());
- if (drag_operation != ui::DragDropTypes::DRAG_NONE)
- return drag_operation;
- }
-
- DCHECK(!initiating_drag_ ||
- !GetRenderText()->IsPointInSelection(event.location()));
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
-
- gfx::SelectionModel drop_destination_model =
- GetRenderText()->FindCursorPosition(event.location());
- string16 text;
- event.data().GetString(&text);
- text = GetTextForDisplay(text);
-
- // Delete the current selection for a drag and drop within this view.
- const bool move = initiating_drag_ && !event.IsControlDown() &&
- event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
- if (move) {
- // Adjust the drop destination if it is on or after the current selection.
- size_t drop = drop_destination_model.caret_pos();
- drop -= GetSelectedRange().Intersect(gfx::Range(0, drop)).length();
- model_->DeleteSelectionAndInsertTextAt(text, drop);
- } else {
- model_->MoveCursorTo(drop_destination_model);
- // Drop always inserts text even if the textfield is not in insert mode.
- model_->InsertText(text);
- }
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
- return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
-}
-
-void NativeTextfieldViews::OnDragDone() {
- initiating_drag_ = false;
- is_drop_cursor_visible_ = false;
-}
-
-void NativeTextfieldViews::OnPaint(gfx::Canvas* canvas) {
- OnPaintBackground(canvas);
- PaintTextAndCursor(canvas);
- if (textfield_->draw_border())
- OnPaintBorder(canvas);
-}
-
-void NativeTextfieldViews::OnFocus() {
- NOTREACHED();
-}
-
-void NativeTextfieldViews::OnBlur() {
- NOTREACHED();
-}
-
-void NativeTextfieldViews::OnNativeThemeChanged(const ui::NativeTheme* theme) {
- UpdateColorsFromTheme(theme);
-}
-
-void NativeTextfieldViews::SelectRect(const gfx::Point& start,
- const gfx::Point& end) {
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
- return;
-
- gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start);
- gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end);
- gfx::SelectionModel selection(
- gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()),
- end_caret.caret_affinity());
-
- OnBeforeUserAction();
- model_->SelectSelectionModel(selection);
- OnCaretBoundsChanged();
- SchedulePaint();
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::MoveCaretTo(const gfx::Point& point) {
- SelectRect(point, point);
-}
-
-void NativeTextfieldViews::GetSelectionEndPoints(gfx::Rect* p1,
- gfx::Rect* p2) {
- gfx::RenderText* render_text = GetRenderText();
- const gfx::SelectionModel& sel = render_text->selection_model();
- gfx::SelectionModel start_sel =
- render_text->GetSelectionModelForSelectionStart();
- *p1 = render_text->GetCursorBounds(start_sel, true);
- *p2 = render_text->GetCursorBounds(sel, true);
-}
-
-gfx::Rect NativeTextfieldViews::GetBounds() {
- return bounds();
-}
-
-gfx::NativeView NativeTextfieldViews::GetNativeView() {
- return GetWidget()->GetNativeView();
-}
-
-void NativeTextfieldViews::ConvertPointToScreen(gfx::Point* point) {
- View::ConvertPointToScreen(this, point);
-}
-
-void NativeTextfieldViews::ConvertPointFromScreen(gfx::Point* point) {
- View::ConvertPointFromScreen(this, point);
-}
-
-bool NativeTextfieldViews::DrawsHandles() {
- return false;
-}
-
-void NativeTextfieldViews::OpenContextMenu(const gfx::Point& anchor) {
- touch_selection_controller_.reset();
- ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU);
-}
-
-gfx::NativeCursor NativeTextfieldViews::GetCursor(const ui::MouseEvent& event) {
- bool in_selection = GetRenderText()->IsPointInSelection(event.location());
- bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
- bool text_cursor = !initiating_drag_ && (drag_event || !in_selection);
-#if defined(USE_AURA)
- return text_cursor ? ui::kCursorIBeam : ui::kCursorNull;
-#elif defined(OS_WIN)
- static HCURSOR ibeam = LoadCursor(NULL, IDC_IBEAM);
- static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
- return text_cursor ? ibeam : arrow;
-#endif
-}
-
-/////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, ContextMenuController overrides:
-void NativeTextfieldViews::ShowContextMenuForView(
- View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) {
- UpdateContextMenu();
- if (context_menu_runner_->RunMenuAt(GetWidget(), NULL,
- gfx::Rect(point, gfx::Size()), views::MenuItemView::TOPLEFT,
- source_type,
- MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
- MenuRunner::MENU_DELETED)
- return;
-}
-
-/////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, views::DragController overrides:
-void NativeTextfieldViews::WriteDragDataForView(views::View* sender,
- const gfx::Point& press_pt,
- OSExchangeData* data) {
- DCHECK_NE(ui::DragDropTypes::DRAG_NONE,
- GetDragOperationsForView(sender, press_pt));
- data->SetString(GetSelectedText());
- scoped_ptr<gfx::Canvas> canvas(
- views::GetCanvasForDragImage(textfield_->GetWidget(), size()));
- GetRenderText()->DrawSelectedTextForDrag(canvas.get());
- drag_utils::SetDragImageOnDataObject(*canvas, size(),
- press_pt.OffsetFromOrigin(),
- data);
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnWriteDragData(data);
-}
-
-int NativeTextfieldViews::GetDragOperationsForView(views::View* sender,
- const gfx::Point& p) {
- int drag_operations = ui::DragDropTypes::DRAG_COPY;
- if (!textfield_->enabled() || textfield_->IsObscured() ||
- !GetRenderText()->IsPointInSelection(p))
- drag_operations = ui::DragDropTypes::DRAG_NONE;
- else if (sender == this && !textfield_->read_only())
- drag_operations =
- ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnGetDragOperationsForTextfield(&drag_operations);
- return drag_operations;
-}
-
-bool NativeTextfieldViews::CanStartDragForView(View* sender,
- const gfx::Point& press_pt,
- const gfx::Point& p) {
- return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt);
-}
-
-/////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, NativeTextifieldWrapper overrides:
-
-string16 NativeTextfieldViews::GetText() const {
- return model_->GetText();
-}
-
-void NativeTextfieldViews::UpdateText() {
- model_->SetText(GetTextForDisplay(textfield_->text()));
- OnCaretBoundsChanged();
- SchedulePaint();
- textfield_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true);
-}
-
-void NativeTextfieldViews::AppendText(const string16& text) {
- if (text.empty())
- return;
- model_->Append(GetTextForDisplay(text));
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-void NativeTextfieldViews::InsertOrReplaceText(const string16& text) {
- if (text.empty())
- return;
- model_->InsertText(text);
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-base::i18n::TextDirection NativeTextfieldViews::GetTextDirection() const {
- return GetRenderText()->GetTextDirection();
-}
-
-string16 NativeTextfieldViews::GetSelectedText() const {
- return model_->GetSelectedText();
-}
-
-void NativeTextfieldViews::SelectAll(bool reversed) {
- model_->SelectAll(reversed);
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-void NativeTextfieldViews::ClearSelection() {
- model_->ClearSelection();
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-void NativeTextfieldViews::UpdateBorder() {
- // By default, if a caller calls Textfield::RemoveBorder() and does not set
- // any explicit margins, they should get zero margins. But also call
- // UpdateXXXMargins() so we respect any explicitly-set margins.
- //
- // NOTE: If someday Textfield supports toggling |draw_border_| back on, we'll
- // need to update this conditional to set the insets to their default values.
- if (!textfield_->draw_border())
- text_border_->SetInsets(0, 0, 0, 0);
- UpdateHorizontalMargins();
- UpdateVerticalMargins();
-}
-
-void NativeTextfieldViews::UpdateTextColor() {
- SetColor(textfield_->GetTextColor());
-}
-
-void NativeTextfieldViews::UpdateBackgroundColor() {
- const SkColor color = textfield_->GetBackgroundColor();
- set_background(Background::CreateSolidBackground(color));
- GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::UpdateReadOnly() {
- OnTextInputTypeChanged();
-}
-
-void NativeTextfieldViews::UpdateFont() {
- GetRenderText()->SetFontList(textfield_->font_list());
- OnCaretBoundsChanged();
-}
-
-void NativeTextfieldViews::UpdateIsObscured() {
- GetRenderText()->SetObscured(textfield_->IsObscured());
- OnCaretBoundsChanged();
- SchedulePaint();
- OnTextInputTypeChanged();
-}
-
-void NativeTextfieldViews::UpdateEnabled() {
- SetEnabled(textfield_->enabled());
- SchedulePaint();
- OnTextInputTypeChanged();
-}
-
-gfx::Insets NativeTextfieldViews::CalculateInsets() {
- return GetInsets();
-}
-
-void NativeTextfieldViews::UpdateHorizontalMargins() {
- int left, right;
- if (!textfield_->GetHorizontalMargins(&left, &right))
- return;
- gfx::Insets inset = GetInsets();
- text_border_->SetInsets(inset.top(), left, inset.bottom(), right);
- OnBoundsChanged(GetBounds());
-}
-
-void NativeTextfieldViews::UpdateVerticalMargins() {
- int top, bottom;
- if (!textfield_->GetVerticalMargins(&top, &bottom))
- return;
- gfx::Insets inset = GetInsets();
- text_border_->SetInsets(top, inset.left(), bottom, inset.right());
- OnBoundsChanged(GetBounds());
-}
-
-bool NativeTextfieldViews::SetFocus() {
- return false;
-}
-
-View* NativeTextfieldViews::GetView() {
- return this;
-}
-
-gfx::NativeView NativeTextfieldViews::GetTestingHandle() const {
- NOTREACHED();
- return NULL;
-}
-
-bool NativeTextfieldViews::IsIMEComposing() const {
- return model_->HasCompositionText();
-}
-
-gfx::Range NativeTextfieldViews::GetSelectedRange() const {
- return GetRenderText()->selection();
-}
-
-void NativeTextfieldViews::SelectRange(const gfx::Range& range) {
- model_->SelectRange(range);
- OnCaretBoundsChanged();
- SchedulePaint();
- textfield_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true);
-}
-
-gfx::SelectionModel NativeTextfieldViews::GetSelectionModel() const {
- return GetRenderText()->selection_model();
-}
-
-void NativeTextfieldViews::SelectSelectionModel(
- const gfx::SelectionModel& sel) {
- model_->SelectSelectionModel(sel);
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-size_t NativeTextfieldViews::GetCursorPosition() const {
- return model_->GetCursorPosition();
-}
-
-bool NativeTextfieldViews::GetCursorEnabled() const {
- return GetRenderText()->cursor_enabled();
-}
-
-void NativeTextfieldViews::SetCursorEnabled(bool enabled) {
- GetRenderText()->SetCursorEnabled(enabled);
-}
-
-bool NativeTextfieldViews::HandleKeyPressed(const ui::KeyEvent& e) {
- TextfieldController* controller = textfield_->GetController();
- bool handled = false;
- if (controller)
- handled = controller->HandleKeyEvent(textfield_, e);
- touch_selection_controller_.reset();
- return handled || HandleKeyEvent(e);
-}
-
-bool NativeTextfieldViews::HandleKeyReleased(const ui::KeyEvent& e) {
- return false; // crbug.com/127520
-}
-
-void NativeTextfieldViews::HandleFocus() {
- GetRenderText()->set_focused(true);
- is_cursor_visible_ = true;
- SchedulePaint();
- GetInputMethod()->OnFocus();
- OnCaretBoundsChanged();
-
- const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
- if (caret_blink_ms != 0) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&NativeTextfieldViews::UpdateCursor,
- cursor_timer_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(caret_blink_ms));
- }
-}
-
-void NativeTextfieldViews::HandleBlur() {
- GetRenderText()->set_focused(false);
- GetInputMethod()->OnBlur();
- // Stop blinking cursor.
- cursor_timer_.InvalidateWeakPtrs();
- if (is_cursor_visible_) {
- is_cursor_visible_ = false;
- RepaintCursor();
- }
-
- touch_selection_controller_.reset();
-}
-
-ui::TextInputClient* NativeTextfieldViews::GetTextInputClient() {
- return textfield_->read_only() ? NULL : this;
-}
-
-void NativeTextfieldViews::ClearEditHistory() {
- model_->ClearEditHistory();
-}
-
-int NativeTextfieldViews::GetFontHeight() {
- return GetRenderText()->font_list().GetHeight();
-}
-
-int NativeTextfieldViews::GetTextfieldBaseline() const {
- return GetRenderText()->GetBaseline();
-}
-
-int NativeTextfieldViews::GetWidthNeededForText() const {
- return GetRenderText()->GetContentWidth() + GetInsets().width();
-}
-
-void NativeTextfieldViews::ExecuteTextCommand(int command_id) {
- ExecuteCommand(command_id, 0);
-}
-
-bool NativeTextfieldViews::HasTextBeingDragged() {
- return initiating_drag_;
-}
-
-gfx::Point NativeTextfieldViews::GetContextMenuLocation() {
- return GetCaretBounds().bottom_right();
-}
-
-/////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides:
-
-bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const {
- return true;
-}
-
-bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const {
- TextfieldController* controller = textfield_->GetController();
- if (controller && controller->HandlesCommand(command_id))
- return controller->IsCommandIdEnabled(command_id);
-
- bool editable = !textfield_->read_only();
- string16 result;
- switch (command_id) {
- case IDS_APP_UNDO:
- return editable && model_->CanUndo();
- case IDS_APP_CUT:
- return editable && model_->HasSelection() && !textfield_->IsObscured();
- case IDS_APP_COPY:
- return model_->HasSelection() && !textfield_->IsObscured();
- case IDS_APP_PASTE:
- ui::Clipboard::GetForCurrentThread()->ReadText(
- ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
- return editable && !result.empty();
- case IDS_APP_DELETE:
- return editable && model_->HasSelection();
- case IDS_APP_SELECT_ALL:
- return !model_->GetText().empty();
- default:
- return controller->IsCommandIdEnabled(command_id);
- }
-}
-
-bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) {
- return false;
-}
-
-bool NativeTextfieldViews::IsItemForCommandIdDynamic(int command_id) const {
- const TextfieldController* controller = textfield_->GetController();
- return controller && controller->IsItemForCommandIdDynamic(command_id);
-}
-
-string16 NativeTextfieldViews::GetLabelForCommandId(int command_id) const {
- const TextfieldController* controller = textfield_->GetController();
- return controller ? controller->GetLabelForCommandId(command_id) : string16();
-}
-
-void NativeTextfieldViews::ExecuteCommand(int command_id, int event_flags) {
- touch_selection_controller_.reset();
- if (!IsCommandIdEnabled(command_id))
- return;
-
- TextfieldController* controller = textfield_->GetController();
- if (controller && controller->HandlesCommand(command_id)) {
- controller->ExecuteCommand(command_id, 0);
- } else {
- bool text_changed = false;
- switch (command_id) {
- case IDS_APP_UNDO:
- OnBeforeUserAction();
- text_changed = model_->Undo();
- UpdateAfterChange(text_changed, text_changed);
- OnAfterUserAction();
- break;
- case IDS_APP_CUT:
- OnBeforeUserAction();
- text_changed = Cut();
- UpdateAfterChange(text_changed, text_changed);
- OnAfterUserAction();
- break;
- case IDS_APP_COPY:
- OnBeforeUserAction();
- Copy();
- OnAfterUserAction();
- break;
- case IDS_APP_PASTE:
- OnBeforeUserAction();
- text_changed = Paste();
- UpdateAfterChange(text_changed, text_changed);
- OnAfterUserAction();
- break;
- case IDS_APP_DELETE:
- OnBeforeUserAction();
- text_changed = model_->Delete();
- UpdateAfterChange(text_changed, text_changed);
- OnAfterUserAction();
- break;
- case IDS_APP_SELECT_ALL:
- OnBeforeUserAction();
- SelectAll(false);
- UpdateAfterChange(false, true);
- OnAfterUserAction();
- break;
- default:
- controller->ExecuteCommand(command_id, 0);
- break;
- }
- }
-}
-
-void NativeTextfieldViews::SetColor(SkColor value) {
- GetRenderText()->SetColor(value);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::ApplyColor(SkColor value, const gfx::Range& range) {
- GetRenderText()->ApplyColor(value, range);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::SetStyle(gfx::TextStyle style, bool value) {
- GetRenderText()->SetStyle(style, value);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::ApplyStyle(gfx::TextStyle style,
- bool value,
- const gfx::Range& range) {
- GetRenderText()->ApplyStyle(style, value, range);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
- // Set the RenderText display area.
- gfx::Insets insets = GetInsets();
- gfx::Rect display_rect(insets.left(),
- insets.top(),
- width() - insets.width(),
- height() - insets.height());
- GetRenderText()->SetDisplayRect(display_rect);
- OnCaretBoundsChanged();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, ui::TextInputClient implementation, private:
-
-void NativeTextfieldViews::SetCompositionText(
- const ui::CompositionText& composition) {
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
- return;
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- model_->SetCompositionText(composition);
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::ConfirmCompositionText() {
- if (!model_->HasCompositionText())
- return;
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- model_->ConfirmCompositionText();
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::ClearCompositionText() {
- if (!model_->HasCompositionText())
- return;
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- model_->CancelCompositionText();
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::InsertText(const string16& text) {
- // TODO(suzhe): Filter invalid characters.
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty())
- return;
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- if (GetRenderText()->insert_mode())
- model_->InsertText(GetTextForDisplay(text));
- else
- model_->ReplaceText(GetTextForDisplay(text));
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::InsertChar(char16 ch, int flags) {
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE ||
- !ShouldInsertChar(ch, flags)) {
- return;
- }
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- if (GetRenderText()->insert_mode())
- model_->InsertChar(ch);
- else
- model_->ReplaceChar(ch);
- skip_input_method_cancel_composition_ = false;
-
- model_->SetText(GetTextForDisplay(GetText()));
-
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-
- if (textfield_->IsObscured()) {
- const base::TimeDelta& reveal_duration =
- textfield_->obscured_reveal_duration();
- if (reveal_duration != base::TimeDelta()) {
- const size_t change_offset = model_->GetCursorPosition();
- DCHECK_GT(change_offset, 0u);
- RevealObscuredChar(change_offset - 1, reveal_duration);
- }
- }
-}
-
-gfx::NativeWindow NativeTextfieldViews::GetAttachedWindow() const {
- // Imagine the following hierarchy.
- // [NativeWidget A] - FocusManager
- // [View]
- // [NativeWidget B]
- // [View]
- // [View X]
- // An important thing is that [NativeWidget A] owns Win32 input focus even
- // when [View X] is logically focused by FocusManager. As a result, an Win32
- // IME may want to interact with the native view of [NativeWidget A] rather
- // than that of [NativeWidget B]. This is why we need to call
- // GetTopLevelWidget() here.
- return GetWidget()->GetTopLevelWidget()->GetNativeView();
-}
-
-ui::TextInputType NativeTextfieldViews::GetTextInputType() const {
- return textfield_->GetTextInputType();
-}
-
-ui::TextInputMode NativeTextfieldViews::GetTextInputMode() const {
- return ui::TEXT_INPUT_MODE_DEFAULT;
-}
-
-bool NativeTextfieldViews::CanComposeInline() const {
- return true;
-}
-
-gfx::Rect NativeTextfieldViews::GetCaretBounds() const {
- // TextInputClient::GetCaretBounds is expected to return a value in screen
- // coordinates.
- gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds();
- ConvertRectToScreen(this, &rect);
- return rect;
-}
-
-bool NativeTextfieldViews::GetCompositionCharacterBounds(
- uint32 index,
- gfx::Rect* rect) const {
- DCHECK(rect);
- if (!HasCompositionText())
- return false;
- const gfx::Range& composition_range = GetRenderText()->GetCompositionRange();
- DCHECK(!composition_range.is_empty());
-
- size_t text_index = composition_range.start() + index;
- if (composition_range.end() <= text_index)
- return false;
- if (!GetRenderText()->IsCursorablePosition(text_index)) {
- text_index = GetRenderText()->IndexOfAdjacentGrapheme(
- text_index, gfx::CURSOR_BACKWARD);
- }
- if (text_index < composition_range.start())
- return false;
- const gfx::SelectionModel caret(text_index, gfx::CURSOR_BACKWARD);
- *rect = GetRenderText()->GetCursorBounds(caret, false);
- ConvertRectToScreen(this, rect);
-
- return true;
-}
-
-bool NativeTextfieldViews::HasCompositionText() const {
- return model_->HasCompositionText();
-}
-
-bool NativeTextfieldViews::GetTextRange(gfx::Range* range) const {
- if (!ImeEditingAllowed())
- return false;
-
- model_->GetTextRange(range);
- return true;
-}
-
-bool NativeTextfieldViews::GetCompositionTextRange(gfx::Range* range) const {
- if (!ImeEditingAllowed())
- return false;
-
- model_->GetCompositionTextRange(range);
- return true;
-}
-
-bool NativeTextfieldViews::GetSelectionRange(gfx::Range* range) const {
- if (!ImeEditingAllowed())
- return false;
- *range = GetSelectedRange();
- return true;
-}
-
-bool NativeTextfieldViews::SetSelectionRange(const gfx::Range& range) {
- if (!ImeEditingAllowed() || !range.IsValid())
- return false;
-
- OnBeforeUserAction();
- SelectRange(range);
- OnAfterUserAction();
- return true;
-}
-
-bool NativeTextfieldViews::DeleteRange(const gfx::Range& range) {
- if (!ImeEditingAllowed() || range.is_empty())
- return false;
-
- OnBeforeUserAction();
- model_->SelectRange(range);
- if (model_->HasSelection()) {
- model_->DeleteSelection();
- UpdateAfterChange(true, true);
- }
- OnAfterUserAction();
- return true;
-}
-
-bool NativeTextfieldViews::GetTextFromRange(
- const gfx::Range& range,
- string16* text) const {
- if (!ImeEditingAllowed() || !range.IsValid())
- return false;
-
- gfx::Range text_range;
- if (!GetTextRange(&text_range) || !text_range.Contains(range))
- return false;
-
- *text = model_->GetTextFromRange(range);
- return true;
-}
-
-void NativeTextfieldViews::OnInputMethodChanged() {
- // TODO(msw): NOTIMPLEMENTED(); see http://crbug.com/140402
-}
-
-bool NativeTextfieldViews::ChangeTextDirectionAndLayoutAlignment(
- base::i18n::TextDirection direction) {
- // Restore text directionality mode when the indicated direction matches the
- // current forced mode; otherwise, force the mode indicated. This helps users
- // manage BiDi text layout without getting stuck in forced LTR or RTL modes.
- const gfx::DirectionalityMode mode = direction == base::i18n::RIGHT_TO_LEFT ?
- gfx::DIRECTIONALITY_FORCE_RTL : gfx::DIRECTIONALITY_FORCE_LTR;
- if (mode == GetRenderText()->directionality_mode())
- GetRenderText()->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT);
- else
- GetRenderText()->SetDirectionalityMode(mode);
- SchedulePaint();
- return true;
-}
-
-void NativeTextfieldViews::ExtendSelectionAndDelete(
- size_t before,
- size_t after) {
- gfx::Range range = GetSelectedRange();
- DCHECK_GE(range.start(), before);
-
- range.set_start(range.start() - before);
- range.set_end(range.end() + after);
- gfx::Range text_range;
- if (GetTextRange(&text_range) && text_range.Contains(range))
- DeleteRange(range);
-}
-
-void NativeTextfieldViews::EnsureCaretInRect(const gfx::Rect& rect) {
-}
-
-void NativeTextfieldViews::OnCandidateWindowShown() {
-}
-
-void NativeTextfieldViews::OnCandidateWindowUpdated() {
-}
-
-void NativeTextfieldViews::OnCandidateWindowHidden() {
-}
-
-void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() {
- if (skip_input_method_cancel_composition_)
- return;
- DCHECK(textfield_->GetInputMethod());
- textfield_->GetInputMethod()->CancelComposition(textfield_);
-}
-
-gfx::RenderText* NativeTextfieldViews::GetRenderText() const {
- return model_->render_text();
-}
-
-string16 NativeTextfieldViews::GetTextForDisplay(const string16& text) {
- return textfield_->style() & Textfield::STYLE_LOWERCASE ?
- base::i18n::ToLower(text) : text;
-}
-
-void NativeTextfieldViews::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
- UpdateTextColor();
- UpdateBackgroundColor();
- gfx::RenderText* render_text = GetRenderText();
- render_text->set_cursor_color(textfield_->GetTextColor());
- render_text->set_selection_color(theme->GetSystemColor(
- ui::NativeTheme::kColorId_TextfieldSelectionColor));
- render_text->set_selection_background_focused_color(theme->GetSystemColor(
- ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused));
-}
-
-void NativeTextfieldViews::UpdateCursor() {
- const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
- is_cursor_visible_ = !is_cursor_visible_ || (caret_blink_ms == 0);
- RepaintCursor();
- if (caret_blink_ms != 0) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&NativeTextfieldViews::UpdateCursor,
- cursor_timer_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(caret_blink_ms));
- }
-}
-
-void NativeTextfieldViews::RepaintCursor() {
- gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
- r.Inset(-1, -1, -1, -1);
- SchedulePaintInRect(r);
-}
-
-void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
- TRACE_EVENT0("views", "NativeTextfieldViews::PaintTextAndCursor");
- canvas->Save();
- GetRenderText()->set_cursor_visible(!is_drop_cursor_visible_ &&
- is_cursor_visible_ && !model_->HasSelection());
- // Draw the text, cursor, and selection.
- GetRenderText()->Draw(canvas);
-
- // Draw the detached drop cursor that marks where the text will be dropped.
- if (is_drop_cursor_visible_)
- GetRenderText()->DrawCursor(canvas, drop_cursor_position_);
-
- // Draw placeholder text if needed.
- if (model_->GetText().empty() &&
- !textfield_->GetPlaceholderText().empty()) {
- canvas->DrawStringInt(
- textfield_->GetPlaceholderText(),
- GetRenderText()->GetPrimaryFont(),
- textfield_->placeholder_text_color(),
- GetRenderText()->display_rect());
- }
- canvas->Restore();
-}
-
-bool NativeTextfieldViews::HandleKeyEvent(const ui::KeyEvent& key_event) {
- // TODO(oshima): Refactor and consolidate with ExecuteCommand.
- if (key_event.type() == ui::ET_KEY_PRESSED) {
- ui::KeyboardCode key_code = key_event.key_code();
- if (key_code == ui::VKEY_TAB || key_event.IsUnicodeKeyCode())
- return false;
-
- OnBeforeUserAction();
- const bool editable = !textfield_->read_only();
- const bool readable = !textfield_->IsObscured();
- const bool shift = key_event.IsShiftDown();
- const bool control = key_event.IsControlDown();
- const bool alt = key_event.IsAltDown() || key_event.IsAltGrDown();
- bool text_changed = false;
- bool cursor_changed = false;
- switch (key_code) {
- case ui::VKEY_Z:
- if (control && !shift && !alt && editable)
- cursor_changed = text_changed = model_->Undo();
- else if (control && shift && !alt && editable)
- cursor_changed = text_changed = model_->Redo();
- break;
- case ui::VKEY_Y:
- if (control && !alt && editable)
- cursor_changed = text_changed = model_->Redo();
- break;
- case ui::VKEY_A:
- if (control && !alt) {
- model_->SelectAll(false);
- cursor_changed = true;
- }
- break;
- case ui::VKEY_X:
- if (control && !alt && editable && readable)
- cursor_changed = text_changed = Cut();
- break;
- case ui::VKEY_C:
- if (control && !alt && readable)
- Copy();
- break;
- case ui::VKEY_V:
- if (control && !alt && editable)
- cursor_changed = text_changed = Paste();
- break;
- case ui::VKEY_RIGHT:
- case ui::VKEY_LEFT: {
- // We should ignore the alt-left/right keys because alt key doesn't make
- // any special effects for them and they can be shortcut keys such like
- // forward/back of the browser history.
- if (alt)
- break;
- const gfx::Range selection_range = GetSelectedRange();
- model_->MoveCursor(
- control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK,
- (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT,
- shift);
- cursor_changed = GetSelectedRange() != selection_range;
- break;
- }
- case ui::VKEY_END:
- case ui::VKEY_HOME:
- if ((key_code == ui::VKEY_HOME) ==
- (GetRenderText()->GetTextDirection() == base::i18n::RIGHT_TO_LEFT))
- model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift);
- else
- model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift);
- cursor_changed = true;
- break;
- case ui::VKEY_BACK:
- case ui::VKEY_DELETE:
- if (!editable)
- break;
- if (!model_->HasSelection()) {
- gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ?
- gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
- if (shift && control) {
- // If both shift and control are pressed, then erase up to the
- // beginning/end of the buffer in ChromeOS. In windows, do nothing.
-#if defined(OS_WIN)
- break;
-#else
- model_->MoveCursor(gfx::LINE_BREAK, direction, true);
-#endif
- } else if (control) {
- // If only control is pressed, then erase the previous/next word.
- model_->MoveCursor(gfx::WORD_BREAK, direction, true);
- }
- }
- if (key_code == ui::VKEY_BACK)
- model_->Backspace();
- else if (shift && model_->HasSelection() && readable)
- Cut();
- else
- model_->Delete();
-
- // Consume backspace and delete keys even if the edit did nothing. This
- // prevents potential unintended side-effects of further event handling.
- text_changed = true;
- break;
- case ui::VKEY_INSERT:
- if (control && !shift && readable)
- Copy();
- else if (shift && !control && editable)
- cursor_changed = text_changed = Paste();
- break;
- default:
- break;
- }
-
- // We must have input method in order to support text input.
- DCHECK(textfield_->GetInputMethod());
-
- UpdateAfterChange(text_changed, cursor_changed);
- OnAfterUserAction();
- return (text_changed || cursor_changed);
- }
- return false;
-}
-
-bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) {
- if (!model_->MoveCursorTo(point, select))
- return false;
- OnCaretBoundsChanged();
- return true;
-}
-
-void NativeTextfieldViews::PropagateTextChange() {
- textfield_->SyncText();
-}
-
-void NativeTextfieldViews::UpdateAfterChange(bool text_changed,
- bool cursor_changed) {
- if (text_changed) {
- PropagateTextChange();
- textfield_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true);
- }
- if (cursor_changed) {
- is_cursor_visible_ = true;
- RepaintCursor();
- if (!text_changed) {
- // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire
- // this if only the selection changed.
- textfield_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true);
- }
- }
- if (text_changed || cursor_changed) {
- OnCaretBoundsChanged();
- SchedulePaint();
- }
-}
-
-void NativeTextfieldViews::UpdateContextMenu() {
- if (!context_menu_contents_.get()) {
- context_menu_contents_.reset(new ui::SimpleMenuModel(this));
- context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
- context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
- context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
- context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
- context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
- context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
- context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
- context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
- IDS_APP_SELECT_ALL);
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->UpdateContextMenu(context_menu_contents_.get());
-
- context_menu_delegate_.reset(
- new views::MenuModelAdapter(context_menu_contents_.get()));
- context_menu_runner_.reset(
- new MenuRunner(new views::MenuItemView(context_menu_delegate_.get())));
- }
-
- context_menu_delegate_->BuildMenu(context_menu_runner_->GetMenu());
-}
-
-void NativeTextfieldViews::OnTextInputTypeChanged() {
- // TODO(suzhe): changed from DCHECK. See http://crbug.com/81320.
- if (textfield_->GetInputMethod())
- textfield_->GetInputMethod()->OnTextInputTypeChanged(textfield_);
-}
-
-void NativeTextfieldViews::OnCaretBoundsChanged() {
- // TODO(suzhe): changed from DCHECK. See http://crbug.com/81320.
- if (textfield_->GetInputMethod())
- textfield_->GetInputMethod()->OnCaretBoundsChanged(textfield_);
-
- // Notify selection controller
- if (touch_selection_controller_.get())
- touch_selection_controller_->SelectionChanged();
-}
-
-void NativeTextfieldViews::OnBeforeUserAction() {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnBeforeUserAction(textfield_);
-}
-
-void NativeTextfieldViews::OnAfterUserAction() {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnAfterUserAction(textfield_);
-}
-
-bool NativeTextfieldViews::Cut() {
- if (!textfield_->read_only() && !textfield_->IsObscured() && model_->Cut()) {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnAfterCutOrCopy();
- return true;
- }
- return false;
-}
-
-bool NativeTextfieldViews::Copy() {
- if (!textfield_->IsObscured() && model_->Copy()) {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnAfterCutOrCopy();
- return true;
- }
- return false;
-}
-
-bool NativeTextfieldViews::Paste() {
- if (textfield_->read_only())
- return false;
-
- const string16 original_text = GetText();
- const bool success = model_->Paste();
-
- if (success) {
- // As Paste is handled in model_->Paste(), the RenderText may contain
- // upper case characters. This is not consistent with other places
- // which keeps RenderText only containing lower case characters.
- string16 new_text = GetTextForDisplay(GetText());
- model_->SetText(new_text);
-
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnAfterPaste();
- }
- return success;
-}
-
-void NativeTextfieldViews::TrackMouseClicks(const ui::MouseEvent& event) {
- if (event.IsOnlyLeftMouseButton()) {
- base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
- if (time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
- !ExceededDragThresholdFromLastClickLocation(event)) {
- // Upon clicking after a triple click, the count should go back to double
- // click and alternate between double and triple. This assignment maps
- // 0 to 1, 1 to 2, 2 to 1.
- aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
- } else {
- aggregated_clicks_ = 0;
- }
- last_click_time_ = event.time_stamp();
- last_click_location_ = event.location();
- }
-}
-
-void NativeTextfieldViews::HandleMousePressEvent(const ui::MouseEvent& event) {
- if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton())
- textfield_->RequestFocus();
-
- if (!event.IsOnlyLeftMouseButton())
- return;
-
- initiating_drag_ = false;
- bool can_drag = true;
-
- switch (aggregated_clicks_) {
- case 0:
- if (can_drag && GetRenderText()->IsPointInSelection(event.location()))
- initiating_drag_ = true;
- else
- MoveCursorTo(event.location(), event.IsShiftDown());
- break;
- case 1:
- MoveCursorTo(event.location(), false);
- model_->SelectWord();
- double_click_word_ = GetRenderText()->selection();
- OnCaretBoundsChanged();
- break;
- case 2:
- model_->SelectAll(false);
- OnCaretBoundsChanged();
- break;
- default:
- NOTREACHED();
- }
- SchedulePaint();
-}
-
-bool NativeTextfieldViews::ImeEditingAllowed() const {
- // We don't allow the input method to retrieve or delete content from a
- // password field.
- ui::TextInputType t = GetTextInputType();
- return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD);
-}
-
-// static
-bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) {
- // Filter out all control characters, including tab and new line characters,
- // and all characters with Alt modifier. But we need to allow characters with
- // AltGr modifier.
- // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different
- // flag that we don't care about.
- return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
- (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN;
-}
-
-void NativeTextfieldViews::CreateTouchSelectionControllerAndNotifyIt() {
- if (!touch_selection_controller_) {
- touch_selection_controller_.reset(
- ui::TouchSelectionController::create(this));
- }
- if (touch_selection_controller_)
- touch_selection_controller_->SelectionChanged();
-}
-
-void NativeTextfieldViews::PlatformGestureEventHandling(
- const ui::GestureEvent* event) {
-#if defined(OS_WIN) && defined(USE_AURA)
- if (event->type() == ui::ET_GESTURE_TAP && !textfield_->read_only())
- base::win::DisplayVirtualKeyboard();
-#endif
-}
-
-void NativeTextfieldViews::RevealObscuredChar(int index,
- const base::TimeDelta& duration) {
- GetRenderText()->SetObscuredRevealIndex(index);
- SchedulePaint();
-
- if (index != -1) {
- obscured_reveal_timer_.Start(
- FROM_HERE,
- duration,
- base::Bind(&NativeTextfieldViews::RevealObscuredChar,
- base::Unretained(this), -1, base::TimeDelta()));
- }
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/textfield/native_textfield_views.h b/chromium/ui/views/controls/textfield/native_textfield_views.h
deleted file mode 100644
index e85f44dd1b6..00000000000
--- a/chromium/ui/views/controls/textfield/native_textfield_views.h
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_
-#define UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "base/timer/timer.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/models/simple_menu_model.h"
-#include "ui/base/touch/touch_editing_controller.h"
-#include "ui/events/event_constants.h"
-#include "ui/gfx/font.h"
-#include "ui/views/border.h"
-#include "ui/views/context_menu_controller.h"
-#include "ui/views/controls/textfield/native_textfield_wrapper.h"
-#include "ui/views/controls/textfield/textfield_views_model.h"
-#include "ui/views/drag_controller.h"
-#include "ui/views/view.h"
-
-namespace base {
-class Time;
-}
-
-namespace gfx {
-class Canvas;
-}
-
-namespace views {
-
-class FocusableBorder;
-class MenuModelAdapter;
-class MenuRunner;
-
-// A views/skia only implementation of NativeTextfieldWrapper.
-// No platform specific code is used.
-// Following features are not yet supported.
-// * BIDI/Complex script.
-// * Support surrogate pair, or maybe we should just use UTF32 internally.
-// * X selection (only if we want to support).
-// Once completed, this will replace Textfield, NativeTextfieldWin and
-// NativeTextfieldGtk.
-class VIEWS_EXPORT NativeTextfieldViews : public View,
- public ui::TouchEditable,
- public ContextMenuController,
- public DragController,
- public NativeTextfieldWrapper,
- public ui::TextInputClient,
- public TextfieldViewsModel::Delegate {
- public:
- explicit NativeTextfieldViews(Textfield* parent);
- virtual ~NativeTextfieldViews();
-
- // View overrides:
- virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
- virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
- virtual bool GetDropFormats(
- int* formats,
- std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
- virtual bool CanDrop(const ui::OSExchangeData& data) OVERRIDE;
- virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
- virtual void OnDragExited() OVERRIDE;
- virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
- virtual void OnDragDone() OVERRIDE;
- virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnFocus() OVERRIDE;
- virtual void OnBlur() OVERRIDE;
- virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
-
- // ui::TouchEditable overrides:
- virtual void SelectRect(const gfx::Point& start,
- const gfx::Point& end) OVERRIDE;
- virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE;
- virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE;
- virtual gfx::Rect GetBounds() OVERRIDE;
- virtual gfx::NativeView GetNativeView() OVERRIDE;
- virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE;
- virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE;
- virtual bool DrawsHandles() OVERRIDE;
- virtual void OpenContextMenu(const gfx::Point& anchor) OVERRIDE;
-
- // ContextMenuController overrides:
- virtual void ShowContextMenuForView(View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) OVERRIDE;
-
- // Overridden from DragController:
- virtual void WriteDragDataForView(View* sender,
- const gfx::Point& press_pt,
- ui::OSExchangeData* data) OVERRIDE;
- virtual int GetDragOperationsForView(View* sender,
- const gfx::Point& p) OVERRIDE;
- virtual bool CanStartDragForView(View* sender,
- const gfx::Point& press_pt,
- const gfx::Point& p) OVERRIDE;
-
- // NativeTextfieldWrapper overrides:
- virtual string16 GetText() const OVERRIDE;
- virtual void UpdateText() OVERRIDE;
- virtual void AppendText(const string16& text) OVERRIDE;
- virtual void InsertOrReplaceText(const string16& text) OVERRIDE;
- virtual base::i18n::TextDirection GetTextDirection() const OVERRIDE;
- virtual string16 GetSelectedText() const OVERRIDE;
- virtual void SelectAll(bool reversed) OVERRIDE;
- virtual void ClearSelection() OVERRIDE;
- virtual void UpdateBorder() OVERRIDE;
- virtual void UpdateTextColor() OVERRIDE;
- virtual void UpdateBackgroundColor() OVERRIDE;
- virtual void UpdateReadOnly() OVERRIDE;
- virtual void UpdateFont() OVERRIDE;
- virtual void UpdateIsObscured() OVERRIDE;
- virtual void UpdateEnabled() OVERRIDE;
- virtual gfx::Insets CalculateInsets() OVERRIDE;
- virtual void UpdateHorizontalMargins() OVERRIDE;
- virtual void UpdateVerticalMargins() OVERRIDE;
- virtual bool SetFocus() OVERRIDE;
- virtual View* GetView() OVERRIDE;
- virtual gfx::NativeView GetTestingHandle() const OVERRIDE;
- virtual bool IsIMEComposing() const OVERRIDE;
- virtual gfx::Range GetSelectedRange() const OVERRIDE;
- virtual void SelectRange(const gfx::Range& range) OVERRIDE;
- virtual gfx::SelectionModel GetSelectionModel() const OVERRIDE;
- virtual void SelectSelectionModel(const gfx::SelectionModel& sel) OVERRIDE;
- virtual size_t GetCursorPosition() const OVERRIDE;
- virtual bool GetCursorEnabled() const OVERRIDE;
- virtual void SetCursorEnabled(bool enabled) OVERRIDE;
- virtual bool HandleKeyPressed(const ui::KeyEvent& e) OVERRIDE;
- virtual bool HandleKeyReleased(const ui::KeyEvent& e) OVERRIDE;
- virtual void HandleFocus() OVERRIDE;
- virtual void HandleBlur() OVERRIDE;
- virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
- virtual void SetColor(SkColor value) OVERRIDE;
- virtual void ApplyColor(SkColor value, const gfx::Range& range) OVERRIDE;
- virtual void SetStyle(gfx::TextStyle style, bool value) OVERRIDE;
- virtual void ApplyStyle(gfx::TextStyle style,
- bool value,
- const gfx::Range& range) OVERRIDE;
- virtual void ClearEditHistory() OVERRIDE;
- virtual int GetFontHeight() OVERRIDE;
- virtual int GetTextfieldBaseline() const OVERRIDE;
- virtual int GetWidthNeededForText() const OVERRIDE;
- virtual void ExecuteTextCommand(int command_id) OVERRIDE;
- virtual bool HasTextBeingDragged() OVERRIDE;
- virtual gfx::Point GetContextMenuLocation() OVERRIDE;
-
- // ui::SimpleMenuModel::Delegate overrides
- virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
- virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- ui::Accelerator* accelerator) OVERRIDE;
- virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
- virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
- virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
-
- // class name of internal
- static const char kViewClassName[];
-
- protected:
- // View override.
- virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
-
- private:
- friend class NativeTextfieldViewsTest;
- friend class TouchSelectionControllerImplTest;
-
- // Overridden from ui::TextInputClient:
- virtual void SetCompositionText(
- const ui::CompositionText& composition) OVERRIDE;
- virtual void ConfirmCompositionText() OVERRIDE;
- virtual void ClearCompositionText() OVERRIDE;
- virtual void InsertText(const string16& text) OVERRIDE;
- virtual void InsertChar(char16 ch, int flags) OVERRIDE;
- virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
- virtual ui::TextInputType GetTextInputType() const OVERRIDE;
- virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
- virtual bool CanComposeInline() const OVERRIDE;
- virtual gfx::Rect GetCaretBounds() const OVERRIDE;
- virtual bool GetCompositionCharacterBounds(uint32 index,
- gfx::Rect* rect) const OVERRIDE;
- virtual bool HasCompositionText() const OVERRIDE;
- virtual bool GetTextRange(gfx::Range* range) const OVERRIDE;
- virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE;
- virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE;
- virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
- virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
- virtual bool GetTextFromRange(const gfx::Range& range,
- string16* text) const OVERRIDE;
- virtual void OnInputMethodChanged() OVERRIDE;
- virtual bool ChangeTextDirectionAndLayoutAlignment(
- base::i18n::TextDirection direction) OVERRIDE;
- virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE;
- virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE;
- virtual void OnCandidateWindowShown() OVERRIDE;
- virtual void OnCandidateWindowUpdated() OVERRIDE;
- virtual void OnCandidateWindowHidden() OVERRIDE;
-
- // Overridden from TextfieldViewsModel::Delegate:
- virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE;
-
- // Returns the TextfieldViewsModel's text/cursor/selection rendering model.
- gfx::RenderText* GetRenderText() const;
-
- // Converts |text| according to textfield style, e.g. lower case if
- // |textfield_| has STYLE_LOWERCASE style.
- string16 GetTextForDisplay(const string16& text);
-
- // Updates any colors that have not been explicitly set from the theme.
- void UpdateColorsFromTheme(const ui::NativeTheme* theme);
-
- // A callback function to periodically update the cursor state.
- void UpdateCursor();
-
- // Repaint the cursor.
- void RepaintCursor();
-
- // Update the cursor_bounds and text_offset.
- void UpdateCursorBoundsAndTextOffset(size_t cursor_pos, bool insert_mode);
-
- void PaintTextAndCursor(gfx::Canvas* canvas);
-
- // Handle the keyevent.
- bool HandleKeyEvent(const ui::KeyEvent& key_event);
-
- // Helper function to call MoveCursorTo on the TextfieldViewsModel.
- bool MoveCursorTo(const gfx::Point& point, bool select);
-
- // Utility function to inform the parent textfield (and its controller if any)
- // that the text in the textfield has changed.
- void PropagateTextChange();
-
- // Does necessary updates when the text and/or the position of the cursor
- // changed.
- void UpdateAfterChange(bool text_changed, bool cursor_changed);
-
- // Utility function to prepare the context menu.
- void UpdateContextMenu();
-
- // Convenience method to call InputMethod::OnTextInputTypeChanged();
- void OnTextInputTypeChanged();
-
- // Convenience method to call InputMethod::OnCaretBoundsChanged();
- void OnCaretBoundsChanged();
-
- // Convenience method to call TextfieldController::OnBeforeUserAction();
- void OnBeforeUserAction();
-
- // Convenience method to call TextfieldController::OnAfterUserAction();
- void OnAfterUserAction();
-
- // Calls |model_->Cut()| and notifies TextfieldController on success.
- bool Cut();
-
- // Calls |model_->Copy()| and notifies TextfieldController on success.
- bool Copy();
-
- // Calls |model_->Paste()| and calls TextfieldController::ContentsChanged()
- // explicitly if paste succeeded.
- bool Paste();
-
- // Tracks the mouse clicks for single/double/triple clicks.
- void TrackMouseClicks(const ui::MouseEvent& event);
-
- // Handles mouse press events.
- void HandleMousePressEvent(const ui::MouseEvent& event);
-
- // Returns true if the current text input type allows access by the IME.
- bool ImeEditingAllowed() const;
-
- // Returns true if distance between |event| and |last_click_location_|
- // exceeds the drag threshold.
- bool ExceededDragThresholdFromLastClickLocation(const ui::MouseEvent& event);
-
- // Checks if a char is ok to be inserted into the textfield. The |ch| is a
- // modified character, i.e., modifiers took effect when generating this char.
- static bool ShouldInsertChar(char16 ch, int flags);
-
- void CreateTouchSelectionControllerAndNotifyIt();
-
- // Platform specific gesture event handling.
- void PlatformGestureEventHandling(const ui::GestureEvent* event);
-
- // Reveals the obscured char at |index| for the given |duration|. If |index|
- // is -1, existing revealed index will be cleared.
- void RevealObscuredChar(int index, const base::TimeDelta& duration);
-
- // The parent textfield, the owner of this object.
- Textfield* textfield_;
-
- // The text model.
- scoped_ptr<TextfieldViewsModel> model_;
-
- // The focusable border. This is always non-NULL, but may not actually be
- // drawn. If it is not drawn, then by default it's also zero-sized unless the
- // Textfield has explicitly-set margins.
- FocusableBorder* text_border_;
-
- // The textfield's text and drop cursor visibility.
- bool is_cursor_visible_;
-
- // The drop cursor is a visual cue for where dragged text will be dropped.
- bool is_drop_cursor_visible_;
- // Position of the drop cursor, if it is visible.
- gfx::SelectionModel drop_cursor_position_;
-
- // True if InputMethod::CancelComposition() should not be called.
- bool skip_input_method_cancel_composition_;
-
- // Is the user potentially dragging and dropping from this view?
- bool initiating_drag_;
-
- // A runnable method factory for callback to update the cursor.
- base::WeakPtrFactory<NativeTextfieldViews> cursor_timer_;
-
- // State variables used to track double and triple clicks.
- size_t aggregated_clicks_;
- base::TimeDelta last_click_time_;
- gfx::Point last_click_location_;
- gfx::Range double_click_word_;
-
- // Context menu and its content list for the textfield.
- scoped_ptr<ui::SimpleMenuModel> context_menu_contents_;
- scoped_ptr<views::MenuModelAdapter> context_menu_delegate_;
- scoped_ptr<views::MenuRunner> context_menu_runner_;
-
- scoped_ptr<ui::TouchSelectionController> touch_selection_controller_;
-
- // A timer to control the duration of showing the last typed char in
- // obscured text. When the timer is running, the last typed char is shown
- // and when the time expires, the last typed char is obscured.
- base::OneShotTimer<NativeTextfieldViews> obscured_reveal_timer_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeTextfieldViews);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_
diff --git a/chromium/ui/views/controls/textfield/native_textfield_wrapper.h b/chromium/ui/views/controls/textfield/native_textfield_wrapper.h
deleted file mode 100644
index eafd2f59dd7..00000000000
--- a/chromium/ui/views/controls/textfield/native_textfield_wrapper.h
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WRAPPER_H_
-#define UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WRAPPER_H_
-
-#include "base/i18n/rtl.h"
-#include "base/strings/string16.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/range/range.h"
-#include "ui/gfx/selection_model.h"
-#include "ui/gfx/text_constants.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Insets;
-class Point;
-} // namespace gfx
-
-namespace ui {
-class KeyEvent;
-class TextInputClient;
-} // namespace ui
-
-namespace views {
-
-class Textfield;
-class View;
-
-// An interface implemented by an object that provides a platform-native
-// text field.
-class VIEWS_EXPORT NativeTextfieldWrapper {
- public:
- // The Textfield calls this when it is destroyed to clean up the wrapper
- // object.
- virtual ~NativeTextfieldWrapper() {}
-
- // Gets the text displayed in the wrapped native text field.
- virtual string16 GetText() const = 0;
-
- // Updates the text displayed with the text held by the Textfield.
- virtual void UpdateText() = 0;
-
- // Adds the specified text to the text already displayed by the wrapped native
- // text field.
- virtual void AppendText(const string16& text) = 0;
-
- // Inserts |text| at the current cursor position, replacing any selected text.
- virtual void InsertOrReplaceText(const string16& text) = 0;
-
- // Returns the text direction.
- virtual base::i18n::TextDirection GetTextDirection() const = 0;
-
- // Gets the text that is selected in the wrapped native text field.
- virtual string16 GetSelectedText() const = 0;
-
- // Select the entire text range. If |reversed| is true, the range will end at
- // the logical beginning of the text; this generally shows the leading portion
- // of text that overflows its display area.
- virtual void SelectAll(bool reversed) = 0;
-
- // Clears the selection within the edit field and sets the caret to the end.
- virtual void ClearSelection() = 0;
-
- // Updates whether there is a visible border.
- virtual void UpdateBorder() = 0;
-
- // Updates the text color used when painting the native text field.
- virtual void UpdateTextColor() = 0;
-
- // Updates the background color used when painting the native text field.
- virtual void UpdateBackgroundColor() = 0;
-
- // Updates the read-only state of the native text field.
- virtual void UpdateReadOnly() = 0;
-
- // Updates the font used to render text in the native text field.
- virtual void UpdateFont() = 0;
-
- // Updates the visibility of the text in the native text field.
- virtual void UpdateIsObscured() = 0;
-
- // Updates the enabled state of the native text field.
- virtual void UpdateEnabled() = 0;
-
- // Returns the insets for the text field.
- virtual gfx::Insets CalculateInsets() = 0;
-
- // Updates the horizontal margins for the native text field.
- virtual void UpdateHorizontalMargins() = 0;
-
- // Updates the vertical margins for the native text field.
- virtual void UpdateVerticalMargins() = 0;
-
- // Sets the focus to the text field. Returns false if the wrapper
- // didn't take focus.
- virtual bool SetFocus() = 0;
-
- // Retrieves the views::View that hosts the native control.
- virtual View* GetView() = 0;
-
- // Returns a handle to the underlying native view for testing.
- virtual gfx::NativeView GetTestingHandle() const = 0;
-
- // Returns whether or not an IME is composing text.
- virtual bool IsIMEComposing() const = 0;
-
- // Gets the selected range.
- virtual gfx::Range GetSelectedRange() const = 0;
-
- // Selects the text given by |range|.
- virtual void SelectRange(const gfx::Range& range) = 0;
-
- // Gets the selection model.
- virtual gfx::SelectionModel GetSelectionModel() const = 0;
-
- // Selects the text given by |sel|.
- virtual void SelectSelectionModel(const gfx::SelectionModel& sel) = 0;
-
- // Returns the currnet cursor position.
- virtual size_t GetCursorPosition() const = 0;
-
- // Get or set whether or not the cursor is enabled.
- virtual bool GetCursorEnabled() const = 0;
- virtual void SetCursorEnabled(bool enabled) = 0;
-
- // Following methods are to forward key/focus related events to the
- // views wrapper so that TextfieldViews can handle key inputs without
- // having focus.
-
- // Invoked when a key is pressed/release on Textfield. Subclasser
- // should return true if the event has been processed and false
- // otherwise.
- // See also View::OnKeyPressed/OnKeyReleased.
- virtual bool HandleKeyPressed(const ui::KeyEvent& e) = 0;
- virtual bool HandleKeyReleased(const ui::KeyEvent& e) = 0;
-
- // Invoked when focus is being moved from or to the Textfield.
- // See also View::OnFocus/OnBlur.
- virtual void HandleFocus() = 0;
- virtual void HandleBlur() = 0;
-
- // Returns the View's TextInputClient instance or NULL if the View doesn't
- // support text input.
- virtual ui::TextInputClient* GetTextInputClient() = 0;
-
- // Set the text colors; see the corresponding Textfield functions for details.
- virtual void SetColor(SkColor value) = 0;
- virtual void ApplyColor(SkColor value, const gfx::Range& range) = 0;
-
- // Set the text styles; see the corresponding Textfield functions for details.
- virtual void SetStyle(gfx::TextStyle style, bool value) = 0;
- virtual void ApplyStyle(gfx::TextStyle style,
- bool value,
- const gfx::Range& range) = 0;
-
- // Clears Edit history.
- virtual void ClearEditHistory() = 0;
-
- // Get the height in pixels of the first font used in this textfield.
- virtual int GetFontHeight() = 0;
-
- // Returns the baseline of the textfield. This should not take into account
- // any insets.
- virtual int GetTextfieldBaseline() const = 0;
-
- // Returns the width necessary to display the current text, including any
- // necessary space for the cursor or border/margin.
- virtual int GetWidthNeededForText() const = 0;
-
- // Performs the action associated with the specified command id. Not called
- // ExecuteCommand to avoid name clash.
- virtual void ExecuteTextCommand(int command_id) = 0;
-
- // Returns whether there is a drag operation originating from the textfield.
- virtual bool HasTextBeingDragged() = 0;
-
- // Returns the location for keyboard-triggered context menus.
- virtual gfx::Point GetContextMenuLocation() = 0;
-
- // Creates an appropriate NativeTextfieldWrapper for the platform.
- static NativeTextfieldWrapper* CreateWrapper(Textfield* field);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WRAPPER_H_
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index de590dc304c..f28f8f27e18 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -6,40 +6,235 @@
#include <string>
-#include "base/command_line.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
-#include "ui/base/ime/text_input_type.h"
+#include "base/debug/trace_event.h"
+#include "grit/ui_strings.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/drag_utils.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_switches.h"
+#include "ui/base/ui_base_switches_util.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/display.h"
#include "ui/gfx/insets.h"
-#include "ui/gfx/range/range.h"
-#include "ui/gfx/selection_model.h"
+#include "ui/gfx/screen.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/focusable_border.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/controls/textfield/native_textfield_views.h"
-#include "ui/views/controls/textfield/native_textfield_wrapper.h"
#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/drag_utils.h"
+#include "ui/views/ime/input_method.h"
+#include "ui/views/metrics.h"
+#include "ui/views/native_cursor.h"
#include "ui/views/painter.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "base/strings/utf_string_conversions.h"
+#include "ui/events/linux/text_edit_command_auralinux.h"
+#include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h"
+#endif
+
+namespace views {
+
namespace {
// Default placeholder text color.
const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
-gfx::FontList GetDefaultFontList() {
- return ResourceBundle::GetSharedInstance().GetFontList(
- ResourceBundle::BaseFont);
+const int kNoCommand = 0;
+
+void ConvertRectToScreen(const View* src, gfx::Rect* r) {
+ DCHECK(src);
+
+ gfx::Point new_origin = r->origin();
+ View::ConvertPointToScreen(src, &new_origin);
+ r->set_origin(new_origin);
}
-} // namespace
+// Get the drag selection timer delay, respecting animation scaling for testing.
+int GetDragSelectionDelay() {
+ switch (ui::ScopedAnimationDurationScaleMode::duration_scale_mode()) {
+ case ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION: return 100;
+ case ui::ScopedAnimationDurationScaleMode::FAST_DURATION: return 25;
+ case ui::ScopedAnimationDurationScaleMode::SLOW_DURATION: return 400;
+ case ui::ScopedAnimationDurationScaleMode::ZERO_DURATION: return 0;
+ }
+ return 100;
+}
+
+// Get the default command for a given key |event| and selection state.
+int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) {
+ if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
+ return kNoCommand;
+
+ const bool shift = event.IsShiftDown();
+ const bool control = event.IsControlDown();
+ const bool alt = event.IsAltDown() || event.IsAltGrDown();
+ switch (event.key_code()) {
+ case ui::VKEY_Z:
+ if (control && !shift && !alt)
+ return IDS_APP_UNDO;
+ return (control && shift && !alt) ? IDS_APP_REDO : kNoCommand;
+ case ui::VKEY_Y:
+ return (control && !alt) ? IDS_APP_REDO : kNoCommand;
+ case ui::VKEY_A:
+ return (control && !alt) ? IDS_APP_SELECT_ALL : kNoCommand;
+ case ui::VKEY_X:
+ return (control && !alt) ? IDS_APP_CUT : kNoCommand;
+ case ui::VKEY_C:
+ return (control && !alt) ? IDS_APP_COPY : kNoCommand;
+ case ui::VKEY_V:
+ return (control && !alt) ? IDS_APP_PASTE : kNoCommand;
+ case ui::VKEY_RIGHT:
+ // Ignore alt+right, which may be a browser navigation shortcut.
+ if (alt)
+ return kNoCommand;
+ if (!shift)
+ return control ? IDS_MOVE_WORD_RIGHT : IDS_MOVE_RIGHT;
+ return control ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
+ IDS_MOVE_RIGHT_AND_MODIFY_SELECTION;
+ case ui::VKEY_LEFT:
+ // Ignore alt+left, which may be a browser navigation shortcut.
+ if (alt)
+ return kNoCommand;
+ if (!shift)
+ return control ? IDS_MOVE_WORD_LEFT : IDS_MOVE_LEFT;
+ return control ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
+ IDS_MOVE_LEFT_AND_MODIFY_SELECTION;
+ case ui::VKEY_HOME:
+ return shift ? IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION :
+ IDS_MOVE_TO_BEGINNING_OF_LINE;
+ case ui::VKEY_END:
+ return shift ? IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION :
+ IDS_MOVE_TO_END_OF_LINE;
+ case ui::VKEY_BACK:
+ if (!control || has_selection)
+ return IDS_DELETE_BACKWARD;
+#if defined(OS_LINUX)
+ // Only erase by line break on Linux and ChromeOS.
+ if (shift)
+ return IDS_DELETE_TO_BEGINNING_OF_LINE;
+#endif
+ return IDS_DELETE_WORD_BACKWARD;
+ case ui::VKEY_DELETE:
+ if (!control || has_selection)
+ return (shift && has_selection) ? IDS_APP_CUT : IDS_DELETE_FORWARD;
+#if defined(OS_LINUX)
+ // Only erase by line break on Linux and ChromeOS.
+ if (shift)
+ return IDS_DELETE_TO_END_OF_LINE;
+#endif
+ return IDS_DELETE_WORD_FORWARD;
+ case ui::VKEY_INSERT:
+ if (control && !shift)
+ return IDS_APP_COPY;
+ return (shift && !control) ? IDS_APP_PASTE : kNoCommand;
+ default:
+ return kNoCommand;
+ }
+}
-namespace views {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// Convert a custom text edit |command| to the equivalent views command ID.
+int GetViewsCommand(const ui::TextEditCommandAuraLinux& command, bool rtl) {
+ const bool select = command.extend_selection();
+ switch (command.command_id()) {
+ case ui::TextEditCommandAuraLinux::COPY:
+ return IDS_APP_COPY;
+ case ui::TextEditCommandAuraLinux::CUT:
+ return IDS_APP_CUT;
+ case ui::TextEditCommandAuraLinux::DELETE_BACKWARD:
+ return IDS_DELETE_BACKWARD;
+ case ui::TextEditCommandAuraLinux::DELETE_FORWARD:
+ return IDS_DELETE_FORWARD;
+ case ui::TextEditCommandAuraLinux::DELETE_TO_BEGINING_OF_LINE:
+ case ui::TextEditCommandAuraLinux::DELETE_TO_BEGINING_OF_PARAGRAPH:
+ return IDS_DELETE_TO_BEGINNING_OF_LINE;
+ case ui::TextEditCommandAuraLinux::DELETE_TO_END_OF_LINE:
+ case ui::TextEditCommandAuraLinux::DELETE_TO_END_OF_PARAGRAPH:
+ return IDS_DELETE_TO_END_OF_LINE;
+ case ui::TextEditCommandAuraLinux::DELETE_WORD_BACKWARD:
+ return IDS_DELETE_WORD_BACKWARD;
+ case ui::TextEditCommandAuraLinux::DELETE_WORD_FORWARD:
+ return IDS_DELETE_WORD_FORWARD;
+ case ui::TextEditCommandAuraLinux::INSERT_TEXT:
+ return kNoCommand;
+ case ui::TextEditCommandAuraLinux::MOVE_BACKWARD:
+ if (rtl)
+ return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
+ return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
+ case ui::TextEditCommandAuraLinux::MOVE_DOWN:
+ return IDS_MOVE_DOWN;
+ case ui::TextEditCommandAuraLinux::MOVE_FORWARD:
+ if (rtl)
+ return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
+ return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
+ case ui::TextEditCommandAuraLinux::MOVE_LEFT:
+ return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
+ case ui::TextEditCommandAuraLinux::MOVE_PAGE_DOWN:
+ case ui::TextEditCommandAuraLinux::MOVE_PAGE_UP:
+ return kNoCommand;
+ case ui::TextEditCommandAuraLinux::MOVE_RIGHT:
+ return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
+ case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_DOCUMENT:
+ case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_LINE:
+ case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_PARAGRAPH:
+ return select ? IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION :
+ IDS_MOVE_TO_BEGINNING_OF_LINE;
+ case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_DOCUMENT:
+ case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_LINE:
+ case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_PARAGRAPH:
+ return select ? IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION :
+ IDS_MOVE_TO_END_OF_LINE;
+ case ui::TextEditCommandAuraLinux::MOVE_UP:
+ return IDS_MOVE_UP;
+ case ui::TextEditCommandAuraLinux::MOVE_WORD_BACKWARD:
+ if (rtl) {
+ return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_RIGHT;
+ }
+ return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_LEFT;
+ case ui::TextEditCommandAuraLinux::MOVE_WORD_FORWARD:
+ if (rtl) {
+ return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_LEFT;
+ }
+ return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_RIGHT;
+ case ui::TextEditCommandAuraLinux::MOVE_WORD_LEFT:
+ return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_LEFT;
+ case ui::TextEditCommandAuraLinux::MOVE_WORD_RIGHT:
+ return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_RIGHT;
+ case ui::TextEditCommandAuraLinux::PASTE:
+ return IDS_APP_PASTE;
+ case ui::TextEditCommandAuraLinux::SELECT_ALL:
+ return IDS_APP_SELECT_ALL;
+ case ui::TextEditCommandAuraLinux::SET_MARK:
+ case ui::TextEditCommandAuraLinux::UNSELECT:
+ case ui::TextEditCommandAuraLinux::INVALID_COMMAND:
+ return kNoCommand;
+ }
+ return kNoCommand;
+}
+#endif
+
+} // namespace
// static
const char Textfield::kViewClassName[] = "Textfield";
@@ -56,153 +251,102 @@ size_t Textfield::GetCaretBlinkMs() {
}
Textfield::Textfield()
- : native_wrapper_(NULL),
+ : model_(new TextfieldModel(this)),
controller_(NULL),
- style_(STYLE_DEFAULT),
- font_list_(GetDefaultFontList()),
read_only_(false),
default_width_in_chars_(0),
- draw_border_(true),
- text_color_(SK_ColorBLACK),
use_default_text_color_(true),
- background_color_(SK_ColorWHITE),
use_default_background_color_(true),
- horizontal_margins_were_set_(false),
- vertical_margins_were_set_(false),
- placeholder_text_color_(kDefaultPlaceholderTextColor),
- text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
- weak_ptr_factory_(this) {
- SetFocusable(true);
-
- if (ViewsDelegate::views_delegate) {
- obscured_reveal_duration_ = ViewsDelegate::views_delegate->
- GetDefaultTextfieldObscuredRevealDuration();
- }
-
- if (NativeViewHost::kRenderNativeControlFocus)
- focus_painter_ = Painter::CreateDashedFocusPainter();
-}
-
-Textfield::Textfield(StyleFlags style)
- : native_wrapper_(NULL),
- controller_(NULL),
- style_(style),
- font_list_(GetDefaultFontList()),
- read_only_(false),
- default_width_in_chars_(0),
- draw_border_(true),
+ use_default_selection_text_color_(true),
+ use_default_selection_background_color_(true),
text_color_(SK_ColorBLACK),
- use_default_text_color_(true),
background_color_(SK_ColorWHITE),
- use_default_background_color_(true),
- horizontal_margins_were_set_(false),
- vertical_margins_were_set_(false),
+ selection_text_color_(SK_ColorWHITE),
+ selection_background_color_(SK_ColorBLUE),
placeholder_text_color_(kDefaultPlaceholderTextColor),
text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
+ performing_user_action_(false),
+ skip_input_method_cancel_composition_(false),
+ cursor_visible_(false),
+ drop_cursor_visible_(false),
+ initiating_drag_(false),
+ aggregated_clicks_(0),
weak_ptr_factory_(this) {
+ set_context_menu_controller(this);
+ set_drag_controller(this);
+ SetBorder(scoped_ptr<Border>(new FocusableBorder()));
SetFocusable(true);
- if (IsObscured())
- SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
if (ViewsDelegate::views_delegate) {
- obscured_reveal_duration_ = ViewsDelegate::views_delegate->
+ password_reveal_duration_ = ViewsDelegate::views_delegate->
GetDefaultTextfieldObscuredRevealDuration();
}
-
- if (NativeViewHost::kRenderNativeControlFocus)
- focus_painter_ = Painter::CreateDashedFocusPainter();
-}
-
-Textfield::~Textfield() {
-}
-
-void Textfield::SetController(TextfieldController* controller) {
- controller_ = controller;
}
-TextfieldController* Textfield::GetController() const {
- return controller_;
-}
+Textfield::~Textfield() {}
void Textfield::SetReadOnly(bool read_only) {
// Update read-only without changing the focusable state (or active, etc.).
read_only_ = read_only;
- if (native_wrapper_) {
- native_wrapper_->UpdateReadOnly();
- native_wrapper_->UpdateTextColor();
- native_wrapper_->UpdateBackgroundColor();
- }
-}
-
-bool Textfield::IsObscured() const {
- return style_ & STYLE_OBSCURED;
-}
-
-void Textfield::SetObscured(bool obscured) {
- if (obscured) {
- style_ = static_cast<StyleFlags>(style_ | STYLE_OBSCURED);
- SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
- } else {
- style_ = static_cast<StyleFlags>(style_ & ~STYLE_OBSCURED);
- SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
- }
- if (native_wrapper_)
- native_wrapper_->UpdateIsObscured();
-}
-
-ui::TextInputType Textfield::GetTextInputType() const {
- if (read_only() || !enabled())
- return ui::TEXT_INPUT_TYPE_NONE;
- return text_input_type_;
+ if (GetInputMethod())
+ GetInputMethod()->OnTextInputTypeChanged(this);
+ SetColor(GetTextColor());
+ UpdateBackgroundColor();
}
void Textfield::SetTextInputType(ui::TextInputType type) {
+ GetRenderText()->SetObscured(type == ui::TEXT_INPUT_TYPE_PASSWORD);
text_input_type_ = type;
- bool should_be_obscured = type == ui::TEXT_INPUT_TYPE_PASSWORD;
- if (IsObscured() != should_be_obscured)
- SetObscured(should_be_obscured);
+ OnCaretBoundsChanged();
+ if (GetInputMethod())
+ GetInputMethod()->OnTextInputTypeChanged(this);
+ SchedulePaint();
}
-void Textfield::SetText(const string16& text) {
- text_ = text;
- if (native_wrapper_)
- native_wrapper_->UpdateText();
+void Textfield::SetText(const base::string16& new_text) {
+ model_->SetText(new_text);
+ OnCaretBoundsChanged();
+ SchedulePaint();
+ NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
}
-void Textfield::AppendText(const string16& text) {
- text_ += text;
- if (native_wrapper_)
- native_wrapper_->AppendText(text);
+void Textfield::AppendText(const base::string16& new_text) {
+ if (new_text.empty())
+ return;
+ model_->Append(new_text);
+ OnCaretBoundsChanged();
+ SchedulePaint();
}
-void Textfield::InsertOrReplaceText(const string16& text) {
- if (native_wrapper_) {
- native_wrapper_->InsertOrReplaceText(text);
- text_ = native_wrapper_->GetText();
- }
+void Textfield::InsertOrReplaceText(const base::string16& new_text) {
+ if (new_text.empty())
+ return;
+ model_->InsertText(new_text);
+ OnCaretBoundsChanged();
+ SchedulePaint();
}
base::i18n::TextDirection Textfield::GetTextDirection() const {
- return native_wrapper_ ?
- native_wrapper_->GetTextDirection() : base::i18n::UNKNOWN_DIRECTION;
+ return GetRenderText()->GetTextDirection();
}
-void Textfield::SelectAll(bool reversed) {
- if (native_wrapper_)
- native_wrapper_->SelectAll(reversed);
+base::string16 Textfield::GetSelectedText() const {
+ return model_->GetSelectedText();
}
-string16 Textfield::GetSelectedText() const {
- return native_wrapper_ ? native_wrapper_->GetSelectedText() : string16();
+void Textfield::SelectAll(bool reversed) {
+ model_->SelectAll(reversed);
+ UpdateSelectionClipboard();
+ UpdateAfterChange(false, true);
}
-void Textfield::ClearSelection() const {
- if (native_wrapper_)
- native_wrapper_->ClearSelection();
+void Textfield::ClearSelection() {
+ model_->ClearSelection();
+ UpdateAfterChange(false, true);
}
bool Textfield::HasSelection() const {
- return native_wrapper_ && !native_wrapper_->GetSelectedRange().is_empty();
+ return !GetSelectedRange().is_empty();
}
SkColor Textfield::GetTextColor() const {
@@ -217,14 +361,12 @@ SkColor Textfield::GetTextColor() const {
void Textfield::SetTextColor(SkColor color) {
text_color_ = color;
use_default_text_color_ = false;
- if (native_wrapper_)
- native_wrapper_->UpdateTextColor();
+ SetColor(color);
}
void Textfield::UseDefaultTextColor() {
use_default_text_color_ = true;
- if (native_wrapper_)
- native_wrapper_->UpdateTextColor();
+ SetColor(GetTextColor());
}
SkColor Textfield::GetBackgroundColor() const {
@@ -239,173 +381,149 @@ SkColor Textfield::GetBackgroundColor() const {
void Textfield::SetBackgroundColor(SkColor color) {
background_color_ = color;
use_default_background_color_ = false;
- if (native_wrapper_)
- native_wrapper_->UpdateBackgroundColor();
+ UpdateBackgroundColor();
}
void Textfield::UseDefaultBackgroundColor() {
use_default_background_color_ = true;
- if (native_wrapper_)
- native_wrapper_->UpdateBackgroundColor();
+ UpdateBackgroundColor();
}
-bool Textfield::GetCursorEnabled() const {
- return native_wrapper_ && native_wrapper_->GetCursorEnabled();
+SkColor Textfield::GetSelectionTextColor() const {
+ return use_default_selection_text_color_ ?
+ GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_TextfieldSelectionColor) :
+ selection_text_color_;
}
-void Textfield::SetCursorEnabled(bool enabled) {
- if (native_wrapper_)
- native_wrapper_->SetCursorEnabled(enabled);
+void Textfield::SetSelectionTextColor(SkColor color) {
+ selection_text_color_ = color;
+ use_default_selection_text_color_ = false;
+ GetRenderText()->set_selection_color(GetSelectionTextColor());
+ SchedulePaint();
}
-void Textfield::SetFontList(const gfx::FontList& font_list) {
- font_list_ = font_list;
- if (native_wrapper_)
- native_wrapper_->UpdateFont();
- PreferredSizeChanged();
+void Textfield::UseDefaultSelectionTextColor() {
+ use_default_selection_text_color_ = true;
+ GetRenderText()->set_selection_color(GetSelectionTextColor());
+ SchedulePaint();
}
-const gfx::Font& Textfield::GetPrimaryFont() const {
- return font_list_.GetPrimaryFont();
+SkColor Textfield::GetSelectionBackgroundColor() const {
+ return use_default_selection_background_color_ ?
+ GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused) :
+ selection_background_color_;
}
-void Textfield::SetFont(const gfx::Font& font) {
- SetFontList(gfx::FontList(font));
+void Textfield::SetSelectionBackgroundColor(SkColor color) {
+ selection_background_color_ = color;
+ use_default_selection_background_color_ = false;
+ GetRenderText()->set_selection_background_focused_color(
+ GetSelectionBackgroundColor());
+ SchedulePaint();
}
-void Textfield::SetHorizontalMargins(int left, int right) {
- if (horizontal_margins_were_set_ &&
- left == margins_.left() && right == margins_.right()) {
- return;
- }
- margins_.Set(margins_.top(), left, margins_.bottom(), right);
- horizontal_margins_were_set_ = true;
- if (native_wrapper_)
- native_wrapper_->UpdateHorizontalMargins();
- PreferredSizeChanged();
+void Textfield::UseDefaultSelectionBackgroundColor() {
+ use_default_selection_background_color_ = true;
+ GetRenderText()->set_selection_background_focused_color(
+ GetSelectionBackgroundColor());
+ SchedulePaint();
}
-void Textfield::SetVerticalMargins(int top, int bottom) {
- if (vertical_margins_were_set_ &&
- top == margins_.top() && bottom == margins_.bottom()) {
- return;
- }
- margins_.Set(top, margins_.left(), bottom, margins_.right());
- vertical_margins_were_set_ = true;
- if (native_wrapper_)
- native_wrapper_->UpdateVerticalMargins();
- PreferredSizeChanged();
+bool Textfield::GetCursorEnabled() const {
+ return GetRenderText()->cursor_enabled();
}
-void Textfield::RemoveBorder() {
- if (!draw_border_)
- return;
+void Textfield::SetCursorEnabled(bool enabled) {
+ GetRenderText()->SetCursorEnabled(enabled);
+}
+
+const gfx::FontList& Textfield::GetFontList() const {
+ return GetRenderText()->font_list();
+}
- draw_border_ = false;
- if (native_wrapper_)
- native_wrapper_->UpdateBorder();
+void Textfield::SetFontList(const gfx::FontList& font_list) {
+ GetRenderText()->SetFontList(font_list);
+ OnCaretBoundsChanged();
+ PreferredSizeChanged();
}
base::string16 Textfield::GetPlaceholderText() const {
return placeholder_text_;
}
-bool Textfield::GetHorizontalMargins(int* left, int* right) {
- if (!horizontal_margins_were_set_)
- return false;
-
- *left = margins_.left();
- *right = margins_.right();
- return true;
+gfx::HorizontalAlignment Textfield::GetHorizontalAlignment() const {
+ return GetRenderText()->horizontal_alignment();
}
-bool Textfield::GetVerticalMargins(int* top, int* bottom) {
- if (!vertical_margins_were_set_)
- return false;
-
- *top = margins_.top();
- *bottom = margins_.bottom();
- return true;
+void Textfield::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
+ GetRenderText()->SetHorizontalAlignment(alignment);
}
-void Textfield::UpdateAllProperties() {
- if (native_wrapper_) {
- native_wrapper_->UpdateText();
- native_wrapper_->UpdateTextColor();
- native_wrapper_->UpdateBackgroundColor();
- native_wrapper_->UpdateReadOnly();
- native_wrapper_->UpdateFont();
- native_wrapper_->UpdateEnabled();
- native_wrapper_->UpdateBorder();
- native_wrapper_->UpdateIsObscured();
- native_wrapper_->UpdateHorizontalMargins();
- native_wrapper_->UpdateVerticalMargins();
- }
-}
-
-void Textfield::SyncText() {
- if (native_wrapper_) {
- string16 new_text = native_wrapper_->GetText();
- if (new_text != text_) {
- text_ = new_text;
- if (controller_)
- controller_->ContentsChanged(this, text_);
- }
- }
+void Textfield::ShowImeIfNeeded() {
+ if (enabled() && !read_only())
+ GetInputMethod()->ShowImeIfNeeded();
}
bool Textfield::IsIMEComposing() const {
- return native_wrapper_ && native_wrapper_->IsIMEComposing();
+ return model_->HasCompositionText();
}
-gfx::Range Textfield::GetSelectedRange() const {
- return native_wrapper_->GetSelectedRange();
+const gfx::Range& Textfield::GetSelectedRange() const {
+ return GetRenderText()->selection();
}
void Textfield::SelectRange(const gfx::Range& range) {
- native_wrapper_->SelectRange(range);
+ model_->SelectRange(range);
+ UpdateAfterChange(false, true);
}
-gfx::SelectionModel Textfield::GetSelectionModel() const {
- return native_wrapper_->GetSelectionModel();
+const gfx::SelectionModel& Textfield::GetSelectionModel() const {
+ return GetRenderText()->selection_model();
}
void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) {
- native_wrapper_->SelectSelectionModel(sel);
+ model_->SelectSelectionModel(sel);
+ UpdateAfterChange(false, true);
}
size_t Textfield::GetCursorPosition() const {
- return native_wrapper_->GetCursorPosition();
+ return model_->GetCursorPosition();
}
void Textfield::SetColor(SkColor value) {
- return native_wrapper_->SetColor(value);
+ GetRenderText()->SetColor(value);
+ SchedulePaint();
}
void Textfield::ApplyColor(SkColor value, const gfx::Range& range) {
- return native_wrapper_->ApplyColor(value, range);
+ GetRenderText()->ApplyColor(value, range);
+ SchedulePaint();
}
void Textfield::SetStyle(gfx::TextStyle style, bool value) {
- return native_wrapper_->SetStyle(style, value);
+ GetRenderText()->SetStyle(style, value);
+ SchedulePaint();
}
void Textfield::ApplyStyle(gfx::TextStyle style,
bool value,
const gfx::Range& range) {
- return native_wrapper_->ApplyStyle(style, value, range);
+ GetRenderText()->ApplyStyle(style, value, range);
+ SchedulePaint();
}
void Textfield::ClearEditHistory() {
- native_wrapper_->ClearEditHistory();
+ model_->ClearEditHistory();
}
-void Textfield::SetAccessibleName(const string16& name) {
+void Textfield::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
void Textfield::ExecuteCommand(int command_id) {
- native_wrapper_->ExecuteTextCommand(command_id);
+ ExecuteCommand(command_id, ui::EF_NONE);
}
void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
@@ -413,101 +531,360 @@ void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
}
bool Textfield::HasTextBeingDragged() {
- return native_wrapper_->HasTextBeingDragged();
+ return initiating_drag_;
}
////////////////////////////////////////////////////////////////////////////////
// Textfield, View overrides:
-void Textfield::Layout() {
- if (native_wrapper_) {
- native_wrapper_->GetView()->SetBoundsRect(GetContentsBounds());
- native_wrapper_->GetView()->Layout();
- }
+int Textfield::GetBaseline() const {
+ return GetInsets().top() + GetRenderText()->GetBaseline();
}
-int Textfield::GetBaseline() const {
- gfx::Insets insets = GetTextInsets();
- const int baseline = native_wrapper_ ?
- native_wrapper_->GetTextfieldBaseline() : font_list_.GetBaseline();
- return insets.top() + baseline;
+gfx::Size Textfield::GetPreferredSize() const {
+ const gfx::Insets& insets = GetInsets();
+ return gfx::Size(GetFontList().GetExpectedTextWidth(default_width_in_chars_) +
+ insets.width(), GetFontList().GetHeight() + insets.height());
}
-gfx::Size Textfield::GetPreferredSize() {
- gfx::Insets insets = GetTextInsets();
+const char* Textfield::GetClassName() const {
+ return kViewClassName;
+}
- const int font_height = native_wrapper_ ? native_wrapper_->GetFontHeight() :
- font_list_.GetHeight();
- return gfx::Size(
- GetPrimaryFont().GetExpectedTextWidth(default_width_in_chars_)
- + insets.width(),
- font_height + insets.height());
+gfx::NativeCursor Textfield::GetCursor(const ui::MouseEvent& event) {
+ bool in_selection = GetRenderText()->IsPointInSelection(event.location());
+ bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
+ bool text_cursor = !initiating_drag_ && (drag_event || !in_selection);
+ return text_cursor ? GetNativeIBeamCursor() : gfx::kNullCursor;
}
-void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
- SelectAll(false);
+bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
+ TrackMouseClicks(event);
+
+ if (!controller_ || !controller_->HandleMouseEvent(this, event)) {
+ if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) {
+ RequestFocus();
+ ShowImeIfNeeded();
+ }
+
+ if (event.IsOnlyLeftMouseButton()) {
+ OnBeforeUserAction();
+ initiating_drag_ = false;
+ switch (aggregated_clicks_) {
+ case 0:
+ if (GetRenderText()->IsPointInSelection(event.location()))
+ initiating_drag_ = true;
+ else
+ MoveCursorTo(event.location(), event.IsShiftDown());
+ break;
+ case 1:
+ model_->MoveCursorTo(event.location(), false);
+ model_->SelectWord();
+ UpdateAfterChange(false, true);
+ double_click_word_ = GetRenderText()->selection();
+ break;
+ case 2:
+ SelectAll(false);
+ break;
+ default:
+ NOTREACHED();
+ }
+ OnAfterUserAction();
+ }
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ if (event.IsOnlyMiddleMouseButton()) {
+ if (GetRenderText()->IsPointInSelection(event.location())) {
+ OnBeforeUserAction();
+ ClearSelection();
+ ui::ScopedClipboardWriter(
+ ui::Clipboard::GetForCurrentThread(),
+ ui::CLIPBOARD_TYPE_SELECTION).WriteText(base::string16());
+ OnAfterUserAction();
+ } else if(!read_only()) {
+ PasteSelectionClipboard(event);
+ }
+ }
+#endif
+ }
+
+ return true;
}
-bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
- // Skip any accelerator handling of backspace; textfields handle this key.
- // Also skip processing of [Alt]+<num-pad digit> Unicode alt key codes.
- return e.key_code() == ui::VKEY_BACK || e.IsUnicodeKeyCode();
+bool Textfield::OnMouseDragged(const ui::MouseEvent& event) {
+ last_drag_location_ = event.location();
+
+ // Don't adjust the cursor on a potential drag and drop, or if the mouse
+ // movement from the last mouse click does not exceed the drag threshold.
+ if (initiating_drag_ || !event.IsOnlyLeftMouseButton() ||
+ !ExceededDragThreshold(last_drag_location_ - last_click_location_)) {
+ return true;
+ }
+
+ // A timer is used to continuously scroll while selecting beyond side edges.
+ if ((event.location().x() > 0 && event.location().x() < size().width()) ||
+ GetDragSelectionDelay() == 0) {
+ drag_selection_timer_.Stop();
+ SelectThroughLastDragLocation();
+ } else if (!drag_selection_timer_.IsRunning()) {
+ drag_selection_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromMilliseconds(GetDragSelectionDelay()),
+ this, &Textfield::SelectThroughLastDragLocation);
+ }
+
+ return true;
}
-void Textfield::OnPaint(gfx::Canvas* canvas) {
- View::OnPaint(canvas);
- if (NativeViewHost::kRenderNativeControlFocus)
- Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
+void Textfield::OnMouseReleased(const ui::MouseEvent& event) {
+ OnBeforeUserAction();
+ drag_selection_timer_.Stop();
+ // Cancel suspected drag initiations, the user was clicking in the selection.
+ if (initiating_drag_)
+ MoveCursorTo(event.location(), false);
+ initiating_drag_ = false;
+ UpdateSelectionClipboard();
+ OnAfterUserAction();
+}
+
+bool Textfield::OnKeyPressed(const ui::KeyEvent& event) {
+ bool handled = controller_ && controller_->HandleKeyEvent(this, event);
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
+ ui::GetTextEditKeyBindingsDelegate();
+ std::vector<ui::TextEditCommandAuraLinux> commands;
+ if (!handled && delegate && delegate->MatchEvent(event, &commands)) {
+ const bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ for (size_t i = 0; i < commands.size(); ++i) {
+ const int command = GetViewsCommand(commands[i], rtl);
+ if (IsCommandIdEnabled(command)) {
+ ExecuteCommand(command);
+ handled = true;
+ }
+ }
+ return handled;
+ }
+#endif
+
+ const int command = GetCommandForKeyEvent(event, HasSelection());
+ if (!handled && IsCommandIdEnabled(command)) {
+ ExecuteCommand(command);
+ handled = true;
+ }
+ return handled;
+}
+
+ui::TextInputClient* Textfield::GetTextInputClient() {
+ return read_only_ ? NULL : this;
+}
+
+void Textfield::OnGestureEvent(ui::GestureEvent* event) {
+ switch (event->type()) {
+ case ui::ET_GESTURE_TAP_DOWN:
+ OnBeforeUserAction();
+ RequestFocus();
+ ShowImeIfNeeded();
+
+ // We don't deselect if the point is in the selection
+ // because TAP_DOWN may turn into a LONG_PRESS.
+ if (!GetRenderText()->IsPointInSelection(event->location()))
+ MoveCursorTo(event->location(), false);
+ OnAfterUserAction();
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ OnBeforeUserAction();
+ MoveCursorTo(event->location(), true);
+ OnAfterUserAction();
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_SCROLL_END:
+ case ui::ET_SCROLL_FLING_START:
+ CreateTouchSelectionControllerAndNotifyIt();
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_TAP:
+ if (event->details().tap_count() == 1) {
+ CreateTouchSelectionControllerAndNotifyIt();
+ } else {
+ DestroyTouchSelection();
+ OnBeforeUserAction();
+ SelectAll(false);
+ OnAfterUserAction();
+ event->SetHandled();
+ }
+#if defined(OS_WIN)
+ if (!read_only())
+ base::win::DisplayVirtualKeyboard();
+#endif
+ break;
+ case ui::ET_GESTURE_LONG_PRESS:
+ // If long press happens outside selection, select word and show context
+ // menu (If touch selection is enabled, context menu is shown by the
+ // |touch_selection_controller_|, hence we mark the event handled.
+ // Otherwise, the regular context menu will be shown by views).
+ // If long press happens in selected text and touch drag drop is enabled,
+ // we will turn off touch selection (if one exists) and let views do drag
+ // drop.
+ if (!GetRenderText()->IsPointInSelection(event->location())) {
+ OnBeforeUserAction();
+ model_->SelectWord();
+ touch_selection_controller_.reset(
+ ui::TouchSelectionController::create(this));
+ UpdateAfterChange(false, true);
+ OnAfterUserAction();
+ if (touch_selection_controller_)
+ event->SetHandled();
+ } else if (switches::IsTouchDragDropEnabled()) {
+ initiating_drag_ = true;
+ DestroyTouchSelection();
+ } else {
+ if (!touch_selection_controller_)
+ CreateTouchSelectionControllerAndNotifyIt();
+ if (touch_selection_controller_)
+ event->SetHandled();
+ }
+ return;
+ case ui::ET_GESTURE_LONG_TAP:
+ if (!touch_selection_controller_)
+ CreateTouchSelectionControllerAndNotifyIt();
+
+ // If touch selection is enabled, the context menu on long tap will be
+ // shown by the |touch_selection_controller_|, hence we mark the event
+ // handled so views does not try to show context menu on it.
+ if (touch_selection_controller_)
+ event->SetHandled();
+ break;
+ default:
+ return;
+ }
}
-bool Textfield::OnKeyPressed(const ui::KeyEvent& e) {
- return native_wrapper_ && native_wrapper_->HandleKeyPressed(e);
+void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
+ SelectAll(false);
}
-bool Textfield::OnKeyReleased(const ui::KeyEvent& e) {
- return native_wrapper_ && native_wrapper_->HandleKeyReleased(e);
+bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Skip any accelerator handling that conflicts with custom keybindings.
+ ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
+ ui::GetTextEditKeyBindingsDelegate();
+ std::vector<ui::TextEditCommandAuraLinux> commands;
+ if (delegate && delegate->MatchEvent(event, &commands)) {
+ const bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ for (size_t i = 0; i < commands.size(); ++i)
+ if (IsCommandIdEnabled(GetViewsCommand(commands[i], rtl)))
+ return true;
+ }
+#endif
+
+ // Skip backspace accelerator handling; editable textfields handle this key.
+ // Also skip processing Windows [Alt]+<num-pad digit> Unicode alt-codes.
+ const bool is_backspace = event.key_code() == ui::VKEY_BACK;
+ return (is_backspace && !read_only()) || event.IsUnicodeKeyCode();
}
-bool Textfield::OnMouseDragged(const ui::MouseEvent& e) {
- if (!e.IsOnlyRightMouseButton())
- return View::OnMouseDragged(e);
+bool Textfield::GetDropFormats(
+ int* formats,
+ std::set<OSExchangeData::CustomFormat>* custom_formats) {
+ if (!enabled() || read_only())
+ return false;
+ // TODO(msw): Can we support URL, FILENAME, etc.?
+ *formats = ui::OSExchangeData::STRING;
+ if (controller_)
+ controller_->AppendDropFormats(formats, custom_formats);
return true;
}
-void Textfield::OnFocus() {
- if (native_wrapper_)
- native_wrapper_->HandleFocus();
+bool Textfield::CanDrop(const OSExchangeData& data) {
+ int formats;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+ GetDropFormats(&formats, &custom_formats);
+ return enabled() && !read_only() &&
+ data.HasAnyFormat(formats, custom_formats);
+}
+
+int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) {
+ DCHECK(CanDrop(event.data()));
+ gfx::RenderText* render_text = GetRenderText();
+ const gfx::Range& selection = render_text->selection();
+ drop_cursor_position_ = render_text->FindCursorPosition(event.location());
+ bool in_selection = !selection.is_empty() &&
+ selection.Contains(gfx::Range(drop_cursor_position_.caret_pos()));
+ drop_cursor_visible_ = !in_selection;
+ // TODO(msw): Pan over text when the user drags to the visible text edge.
+ OnCaretBoundsChanged();
+ SchedulePaint();
- // Forward the focus to the wrapper if it exists.
- if (!native_wrapper_ || !native_wrapper_->SetFocus()) {
- // If there is no wrapper or the wrapper didn't take focus, call
- // View::Focus to clear the native focus so that we still get
- // keyboard messages.
- View::OnFocus();
+ if (initiating_drag_) {
+ if (in_selection)
+ return ui::DragDropTypes::DRAG_NONE;
+ return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
+ ui::DragDropTypes::DRAG_MOVE;
}
+ return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
+}
- // Border typically draws focus indicator.
+void Textfield::OnDragExited() {
+ drop_cursor_visible_ = false;
SchedulePaint();
}
-void Textfield::OnBlur() {
- if (native_wrapper_)
- native_wrapper_->HandleBlur();
+int Textfield::OnPerformDrop(const ui::DropTargetEvent& event) {
+ DCHECK(CanDrop(event.data()));
+ drop_cursor_visible_ = false;
- // Border typically draws focus indicator.
- SchedulePaint();
+ if (controller_) {
+ int drag_operation = controller_->OnDrop(event.data());
+ if (drag_operation != ui::DragDropTypes::DRAG_NONE)
+ return drag_operation;
+ }
+
+ gfx::RenderText* render_text = GetRenderText();
+ DCHECK(!initiating_drag_ ||
+ !render_text->IsPointInSelection(event.location()));
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+
+ gfx::SelectionModel drop_destination_model =
+ render_text->FindCursorPosition(event.location());
+ base::string16 new_text;
+ event.data().GetString(&new_text);
+
+ // Delete the current selection for a drag and drop within this view.
+ const bool move = initiating_drag_ && !event.IsControlDown() &&
+ event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
+ if (move) {
+ // Adjust the drop destination if it is on or after the current selection.
+ size_t pos = drop_destination_model.caret_pos();
+ pos -= render_text->selection().Intersect(gfx::Range(0, pos)).length();
+ model_->DeleteSelectionAndInsertTextAt(new_text, pos);
+ } else {
+ model_->MoveCursorTo(drop_destination_model);
+ // Drop always inserts text even if the textfield is not in insert mode.
+ model_->InsertText(new_text);
+ }
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+ return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
+}
+
+void Textfield::OnDragDone() {
+ initiating_drag_ = false;
+ drop_cursor_visible_ = false;
}
-void Textfield::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_TEXT;
+void Textfield::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_TEXT_FIELD;
state->name = accessible_name_;
if (read_only())
- state->state |= ui::AccessibilityTypes::STATE_READONLY;
- if (IsObscured())
- state->state |= ui::AccessibilityTypes::STATE_PROTECTED;
- state->value = text_;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
+ if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD)
+ state->AddStateFlag(ui::AX_STATE_PROTECTED);
+ state->value = text();
- const gfx::Range range = native_wrapper_->GetSelectedRange();
+ const gfx::Range range = GetSelectedRange();
state->selection_start = range.start();
state->selection_end = range.end();
@@ -518,61 +895,881 @@ void Textfield::GetAccessibleState(ui::AccessibleViewState* state) {
}
}
-ui::TextInputClient* Textfield::GetTextInputClient() {
- return native_wrapper_ ? native_wrapper_->GetTextInputClient() : NULL;
+void Textfield::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ GetRenderText()->SetDisplayRect(GetContentsBounds());
+ OnCaretBoundsChanged();
+}
+
+void Textfield::OnEnabledChanged() {
+ View::OnEnabledChanged();
+ if (GetInputMethod())
+ GetInputMethod()->OnTextInputTypeChanged(this);
+ SchedulePaint();
+}
+
+void Textfield::OnPaint(gfx::Canvas* canvas) {
+ OnPaintBackground(canvas);
+ PaintTextAndCursor(canvas);
+ OnPaintBorder(canvas);
+}
+
+void Textfield::OnFocus() {
+ GetRenderText()->set_focused(true);
+ cursor_visible_ = true;
+ SchedulePaint();
+ GetInputMethod()->OnFocus();
+ OnCaretBoundsChanged();
+
+ const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
+ if (caret_blink_ms != 0) {
+ cursor_repaint_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(caret_blink_ms), this,
+ &Textfield::UpdateCursor);
+ }
+
+ View::OnFocus();
+ SchedulePaint();
+}
+
+void Textfield::OnBlur() {
+ GetRenderText()->set_focused(false);
+ GetInputMethod()->OnBlur();
+ cursor_repaint_timer_.Stop();
+ if (cursor_visible_) {
+ cursor_visible_ = false;
+ RepaintCursor();
+ }
+
+ DestroyTouchSelection();
+
+ // Border typically draws focus indicator.
+ SchedulePaint();
}
gfx::Point Textfield::GetKeyboardContextMenuLocation() {
- return native_wrapper_ ? native_wrapper_->GetContextMenuLocation() :
- View::GetKeyboardContextMenuLocation();
+ return GetCaretBounds().bottom_right();
}
-void Textfield::OnEnabledChanged() {
- View::OnEnabledChanged();
- if (native_wrapper_)
- native_wrapper_->UpdateEnabled();
+void Textfield::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ gfx::RenderText* render_text = GetRenderText();
+ render_text->SetColor(GetTextColor());
+ UpdateBackgroundColor();
+ render_text->set_cursor_color(GetTextColor());
+ render_text->set_selection_color(GetSelectionTextColor());
+ render_text->set_selection_background_focused_color(
+ GetSelectionBackgroundColor());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, TextfieldModel::Delegate overrides:
+
+void Textfield::OnCompositionTextConfirmedOrCleared() {
+ if (!skip_input_method_cancel_composition_)
+ GetInputMethod()->CancelComposition(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, ContextMenuController overrides:
+
+void Textfield::ShowContextMenuForView(View* source,
+ const gfx::Point& point,
+ ui::MenuSourceType source_type) {
+ UpdateContextMenu();
+ ignore_result(context_menu_runner_->RunMenuAt(
+ GetWidget(),
+ NULL,
+ gfx::Rect(point, gfx::Size()),
+ MENU_ANCHOR_TOPLEFT,
+ source_type,
+ MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, DragController overrides:
+
+void Textfield::WriteDragDataForView(View* sender,
+ const gfx::Point& press_pt,
+ OSExchangeData* data) {
+ const base::string16& selected_text(GetSelectedText());
+ data->SetString(selected_text);
+ Label label(selected_text, GetFontList());
+ label.SetBackgroundColor(GetBackgroundColor());
+ label.set_subpixel_rendering_enabled(false);
+ gfx::Size size(label.GetPreferredSize());
+ gfx::NativeView native_view = GetWidget()->GetNativeView();
+ gfx::Display display = gfx::Screen::GetScreenFor(native_view)->
+ GetDisplayNearestWindow(native_view);
+ size.SetToMin(gfx::Size(display.size().width(), height()));
+ label.SetBoundsRect(gfx::Rect(size));
+ scoped_ptr<gfx::Canvas> canvas(
+ GetCanvasForDragImage(GetWidget(), label.size()));
+ label.SetEnabledColor(GetTextColor());
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Desktop Linux Aura does not yet support transparency in drag images.
+ canvas->DrawColor(GetBackgroundColor());
+#endif
+ label.Paint(canvas.get(), views::CullSet());
+ const gfx::Vector2d kOffset(-15, 0);
+ drag_utils::SetDragImageOnDataObject(*canvas, kOffset, data);
+ if (controller_)
+ controller_->OnWriteDragData(data);
+}
+
+int Textfield::GetDragOperationsForView(View* sender, const gfx::Point& p) {
+ int drag_operations = ui::DragDropTypes::DRAG_COPY;
+ if (!enabled() || text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD ||
+ !GetRenderText()->IsPointInSelection(p)) {
+ drag_operations = ui::DragDropTypes::DRAG_NONE;
+ } else if (sender == this && !read_only()) {
+ drag_operations =
+ ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
+ }
+ if (controller_)
+ controller_->OnGetDragOperationsForTextfield(&drag_operations);
+ return drag_operations;
}
-void Textfield::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- if (details.is_add && !native_wrapper_ && GetWidget()) {
- // The native wrapper's lifetime will be managed by the view hierarchy after
- // we call AddChildView.
- native_wrapper_ = NativeTextfieldWrapper::CreateWrapper(this);
- AddChildViewAt(native_wrapper_->GetView(), 0);
- Layout();
- UpdateAllProperties();
+bool Textfield::CanStartDragForView(View* sender,
+ const gfx::Point& press_pt,
+ const gfx::Point& p) {
+ return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, ui::TouchEditable overrides:
+
+void Textfield::SelectRect(const gfx::Point& start, const gfx::Point& end) {
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return;
+
+ gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start);
+ gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end);
+ gfx::SelectionModel selection(
+ gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()),
+ end_caret.caret_affinity());
+
+ OnBeforeUserAction();
+ SelectSelectionModel(selection);
+ OnAfterUserAction();
+}
+
+void Textfield::MoveCaretTo(const gfx::Point& point) {
+ SelectRect(point, point);
+}
+
+void Textfield::GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) {
+ gfx::RenderText* render_text = GetRenderText();
+ const gfx::SelectionModel& sel = render_text->selection_model();
+ gfx::SelectionModel start_sel =
+ render_text->GetSelectionModelForSelectionStart();
+ *p1 = render_text->GetCursorBounds(start_sel, true);
+ *p2 = render_text->GetCursorBounds(sel, true);
+}
+
+gfx::Rect Textfield::GetBounds() {
+ return GetLocalBounds();
+}
+
+gfx::NativeView Textfield::GetNativeView() const {
+ return GetWidget()->GetNativeView();
+}
+
+void Textfield::ConvertPointToScreen(gfx::Point* point) {
+ View::ConvertPointToScreen(this, point);
+}
+
+void Textfield::ConvertPointFromScreen(gfx::Point* point) {
+ View::ConvertPointFromScreen(this, point);
+}
+
+bool Textfield::DrawsHandles() {
+ return false;
+}
+
+void Textfield::OpenContextMenu(const gfx::Point& anchor) {
+ DestroyTouchSelection();
+ ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU);
+}
+
+void Textfield::DestroyTouchSelection() {
+ touch_selection_controller_.reset();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, ui::SimpleMenuModel::Delegate overrides:
+
+bool Textfield::IsCommandIdChecked(int command_id) const {
+ return true;
+}
+
+bool Textfield::IsCommandIdEnabled(int command_id) const {
+ base::string16 result;
+ bool editable = !read_only();
+ bool readable = text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD;
+ switch (command_id) {
+ case IDS_APP_UNDO:
+ return editable && model_->CanUndo();
+ case IDS_APP_REDO:
+ return editable && model_->CanRedo();
+ case IDS_APP_CUT:
+ return editable && readable && model_->HasSelection();
+ case IDS_APP_COPY:
+ return readable && model_->HasSelection();
+ case IDS_APP_PASTE:
+ ui::Clipboard::GetForCurrentThread()->ReadText(
+ ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
+ return editable && !result.empty();
+ case IDS_APP_DELETE:
+ return editable && model_->HasSelection();
+ case IDS_APP_SELECT_ALL:
+ return !text().empty();
+ case IDS_DELETE_FORWARD:
+ case IDS_DELETE_BACKWARD:
+ case IDS_DELETE_TO_BEGINNING_OF_LINE:
+ case IDS_DELETE_TO_END_OF_LINE:
+ case IDS_DELETE_WORD_BACKWARD:
+ case IDS_DELETE_WORD_FORWARD:
+ return editable;
+ case IDS_MOVE_LEFT:
+ case IDS_MOVE_LEFT_AND_MODIFY_SELECTION:
+ case IDS_MOVE_RIGHT:
+ case IDS_MOVE_RIGHT_AND_MODIFY_SELECTION:
+ case IDS_MOVE_WORD_LEFT:
+ case IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION:
+ case IDS_MOVE_WORD_RIGHT:
+ case IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION:
+ case IDS_MOVE_TO_BEGINNING_OF_LINE:
+ case IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION:
+ case IDS_MOVE_TO_END_OF_LINE:
+ case IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
+ return true;
+ default:
+ return false;
}
}
-const char* Textfield::GetClassName() const {
- return kViewClassName;
+bool Textfield::GetAcceleratorForCommandId(int command_id,
+ ui::Accelerator* accelerator) {
+ return false;
+}
+
+void Textfield::ExecuteCommand(int command_id, int event_flags) {
+ DestroyTouchSelection();
+ if (!IsCommandIdEnabled(command_id))
+ return;
+
+ bool text_changed = false;
+ bool cursor_changed = false;
+ bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ gfx::VisualCursorDirection begin = rtl ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
+ gfx::VisualCursorDirection end = rtl ? gfx::CURSOR_LEFT : gfx::CURSOR_RIGHT;
+ gfx::SelectionModel selection_model = GetSelectionModel();
+
+ OnBeforeUserAction();
+ switch (command_id) {
+ case IDS_APP_UNDO:
+ text_changed = cursor_changed = model_->Undo();
+ break;
+ case IDS_APP_REDO:
+ text_changed = cursor_changed = model_->Redo();
+ break;
+ case IDS_APP_CUT:
+ text_changed = cursor_changed = Cut();
+ break;
+ case IDS_APP_COPY:
+ Copy();
+ break;
+ case IDS_APP_PASTE:
+ text_changed = cursor_changed = Paste();
+ break;
+ case IDS_APP_DELETE:
+ text_changed = cursor_changed = model_->Delete();
+ break;
+ case IDS_APP_SELECT_ALL:
+ SelectAll(false);
+ break;
+ case IDS_DELETE_BACKWARD:
+ text_changed = cursor_changed = model_->Backspace();
+ break;
+ case IDS_DELETE_FORWARD:
+ text_changed = cursor_changed = model_->Delete();
+ break;
+ case IDS_DELETE_TO_END_OF_LINE:
+ model_->MoveCursor(gfx::LINE_BREAK, end, true);
+ text_changed = cursor_changed = model_->Delete();
+ break;
+ case IDS_DELETE_TO_BEGINNING_OF_LINE:
+ model_->MoveCursor(gfx::LINE_BREAK, begin, true);
+ text_changed = cursor_changed = model_->Backspace();
+ break;
+ case IDS_DELETE_WORD_BACKWARD:
+ model_->MoveCursor(gfx::WORD_BREAK, begin, true);
+ text_changed = cursor_changed = model_->Backspace();
+ break;
+ case IDS_DELETE_WORD_FORWARD:
+ model_->MoveCursor(gfx::WORD_BREAK, end, true);
+ text_changed = cursor_changed = model_->Delete();
+ break;
+ case IDS_MOVE_LEFT:
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ break;
+ case IDS_MOVE_LEFT_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ break;
+ case IDS_MOVE_RIGHT:
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ break;
+ case IDS_MOVE_RIGHT_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ break;
+ case IDS_MOVE_WORD_LEFT:
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false);
+ break;
+ case IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ break;
+ case IDS_MOVE_WORD_RIGHT:
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ break;
+ case IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ break;
+ case IDS_MOVE_TO_BEGINNING_OF_LINE:
+ model_->MoveCursor(gfx::LINE_BREAK, begin, false);
+ break;
+ case IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::LINE_BREAK, begin, true);
+ break;
+ case IDS_MOVE_TO_END_OF_LINE:
+ model_->MoveCursor(gfx::LINE_BREAK, end, false);
+ break;
+ case IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::LINE_BREAK, end, true);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ cursor_changed |= GetSelectionModel() != selection_model;
+ if (cursor_changed)
+ UpdateSelectionClipboard();
+ UpdateAfterChange(text_changed, cursor_changed);
+ OnAfterUserAction();
}
////////////////////////////////////////////////////////////////////////////////
-// Textfield, private:
+// Textfield, ui::TextInputClient overrides:
+
+void Textfield::SetCompositionText(const ui::CompositionText& composition) {
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->SetCompositionText(composition);
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void Textfield::ConfirmCompositionText() {
+ if (!model_->HasCompositionText())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->ConfirmCompositionText();
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void Textfield::ClearCompositionText() {
+ if (!model_->HasCompositionText())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->CancelCompositionText();
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void Textfield::InsertText(const base::string16& new_text) {
+ // TODO(suzhe): Filter invalid characters.
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || new_text.empty())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ if (GetRenderText()->insert_mode())
+ model_->InsertText(new_text);
+ else
+ model_->ReplaceText(new_text);
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void Textfield::InsertChar(base::char16 ch, int flags) {
+ const int kControlModifierMask = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
+ ui::EF_COMMAND_DOWN | ui::EF_ALTGR_DOWN |
+ ui::EF_MOD3_DOWN;
+
+ // Filter out all control characters, including tab and new line characters,
+ // and all characters with Alt modifier. But allow characters with the AltGr
+ // modifier. On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a
+ // different flag that we don't care about.
+ const bool should_insert_char =
+ ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
+ (flags & kControlModifierMask) != ui::EF_ALT_DOWN;
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || !should_insert_char)
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ if (GetRenderText()->insert_mode())
+ model_->InsertChar(ch);
+ else
+ model_->ReplaceChar(ch);
+ skip_input_method_cancel_composition_ = false;
+
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+
+ if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD &&
+ password_reveal_duration_ != base::TimeDelta()) {
+ const size_t change_offset = model_->GetCursorPosition();
+ DCHECK_GT(change_offset, 0u);
+ RevealPasswordChar(change_offset - 1);
+ }
+}
+
+gfx::NativeWindow Textfield::GetAttachedWindow() const {
+ // Imagine the following hierarchy.
+ // [NativeWidget A] - FocusManager
+ // [View]
+ // [NativeWidget B]
+ // [View]
+ // [View X]
+ // An important thing is that [NativeWidget A] owns Win32 input focus even
+ // when [View X] is logically focused by FocusManager. As a result, an Win32
+ // IME may want to interact with the native view of [NativeWidget A] rather
+ // than that of [NativeWidget B]. This is why we need to call
+ // GetTopLevelWidget() here.
+ return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
+}
+
+ui::TextInputType Textfield::GetTextInputType() const {
+ if (read_only() || !enabled())
+ return ui::TEXT_INPUT_TYPE_NONE;
+ return text_input_type_;
+}
+
+ui::TextInputMode Textfield::GetTextInputMode() const {
+ return ui::TEXT_INPUT_MODE_DEFAULT;
+}
+
+bool Textfield::CanComposeInline() const {
+ return true;
+}
+
+gfx::Rect Textfield::GetCaretBounds() const {
+ gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds();
+ ConvertRectToScreen(this, &rect);
+ return rect;
+}
+
+bool Textfield::GetCompositionCharacterBounds(uint32 index,
+ gfx::Rect* rect) const {
+ DCHECK(rect);
+ if (!HasCompositionText())
+ return false;
+ gfx::RenderText* render_text = GetRenderText();
+ const gfx::Range& composition_range = render_text->GetCompositionRange();
+ DCHECK(!composition_range.is_empty());
+
+ size_t text_index = composition_range.start() + index;
+ if (composition_range.end() <= text_index)
+ return false;
+ if (!render_text->IsValidCursorIndex(text_index)) {
+ text_index = render_text->IndexOfAdjacentGrapheme(
+ text_index, gfx::CURSOR_BACKWARD);
+ }
+ if (text_index < composition_range.start())
+ return false;
+ const gfx::SelectionModel caret(text_index, gfx::CURSOR_BACKWARD);
+ *rect = render_text->GetCursorBounds(caret, false);
+ ConvertRectToScreen(this, rect);
+ return true;
+}
+
+bool Textfield::HasCompositionText() const {
+ return model_->HasCompositionText();
+}
+
+bool Textfield::GetTextRange(gfx::Range* range) const {
+ if (!ImeEditingAllowed())
+ return false;
+
+ model_->GetTextRange(range);
+ return true;
+}
+
+bool Textfield::GetCompositionTextRange(gfx::Range* range) const {
+ if (!ImeEditingAllowed())
+ return false;
+
+ model_->GetCompositionTextRange(range);
+ return true;
+}
-gfx::Insets Textfield::GetTextInsets() const {
- gfx::Insets insets = GetInsets();
- if (draw_border_ && native_wrapper_)
- insets += native_wrapper_->CalculateInsets();
- return insets;
+bool Textfield::GetSelectionRange(gfx::Range* range) const {
+ if (!ImeEditingAllowed())
+ return false;
+ *range = GetRenderText()->selection();
+ return true;
+}
+
+bool Textfield::SetSelectionRange(const gfx::Range& range) {
+ if (!ImeEditingAllowed() || !range.IsValid())
+ return false;
+ OnBeforeUserAction();
+ SelectRange(range);
+ OnAfterUserAction();
+ return true;
+}
+
+bool Textfield::DeleteRange(const gfx::Range& range) {
+ if (!ImeEditingAllowed() || range.is_empty())
+ return false;
+
+ OnBeforeUserAction();
+ model_->SelectRange(range);
+ if (model_->HasSelection()) {
+ model_->DeleteSelection();
+ UpdateAfterChange(true, true);
+ }
+ OnAfterUserAction();
+ return true;
+}
+
+bool Textfield::GetTextFromRange(const gfx::Range& range,
+ base::string16* range_text) const {
+ if (!ImeEditingAllowed() || !range.IsValid())
+ return false;
+
+ gfx::Range text_range;
+ if (!GetTextRange(&text_range) || !text_range.Contains(range))
+ return false;
+
+ *range_text = model_->GetTextFromRange(range);
+ return true;
+}
+
+void Textfield::OnInputMethodChanged() {}
+
+bool Textfield::ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) {
+ // Restore text directionality mode when the indicated direction matches the
+ // current forced mode; otherwise, force the mode indicated. This helps users
+ // manage BiDi text layout without getting stuck in forced LTR or RTL modes.
+ const gfx::DirectionalityMode mode = direction == base::i18n::RIGHT_TO_LEFT ?
+ gfx::DIRECTIONALITY_FORCE_RTL : gfx::DIRECTIONALITY_FORCE_LTR;
+ if (mode == GetRenderText()->directionality_mode())
+ GetRenderText()->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT);
+ else
+ GetRenderText()->SetDirectionalityMode(mode);
+ SchedulePaint();
+ return true;
}
-void Textfield::AccessibilitySetValue(const string16& new_value) {
+void Textfield::ExtendSelectionAndDelete(size_t before, size_t after) {
+ gfx::Range range = GetRenderText()->selection();
+ DCHECK_GE(range.start(), before);
+
+ range.set_start(range.start() - before);
+ range.set_end(range.end() + after);
+ gfx::Range text_range;
+ if (GetTextRange(&text_range) && text_range.Contains(range))
+ DeleteRange(range);
+}
+
+void Textfield::EnsureCaretInRect(const gfx::Rect& rect) {}
+
+void Textfield::OnCandidateWindowShown() {}
+
+void Textfield::OnCandidateWindowUpdated() {}
+
+void Textfield::OnCandidateWindowHidden() {}
+
+bool Textfield::IsEditingCommandEnabled(int command_id) {
+ return IsCommandIdEnabled(command_id);
+}
+
+void Textfield::ExecuteEditingCommand(int command_id) {
+ ExecuteCommand(command_id);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, protected:
+
+gfx::RenderText* Textfield::GetRenderText() const {
+ return model_->render_text();
+}
+
+base::string16 Textfield::GetSelectionClipboardText() const {
+ base::string16 selection_clipboard_text;
+ ui::Clipboard::GetForCurrentThread()->ReadText(
+ ui::CLIPBOARD_TYPE_SELECTION, &selection_clipboard_text);
+ return selection_clipboard_text;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, private:
+
+void Textfield::AccessibilitySetValue(const base::string16& new_value) {
if (!read_only()) {
SetText(new_value);
ClearSelection();
}
}
-////////////////////////////////////////////////////////////////////////////////
-// NativeTextfieldWrapper, public:
+void Textfield::UpdateBackgroundColor() {
+ const SkColor color = GetBackgroundColor();
+ set_background(Background::CreateSolidBackground(color));
+ GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF);
+ SchedulePaint();
+}
-// static
-NativeTextfieldWrapper* NativeTextfieldWrapper::CreateWrapper(
- Textfield* field) {
- return new NativeTextfieldViews(field);
+void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) {
+ if (text_changed) {
+ if (controller_)
+ controller_->ContentsChanged(this, text());
+ NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
+ }
+ if (cursor_changed) {
+ cursor_visible_ = true;
+ RepaintCursor();
+ if (cursor_repaint_timer_.IsRunning())
+ cursor_repaint_timer_.Reset();
+ if (!text_changed) {
+ // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire
+ // this if only the selection changed.
+ NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION_CHANGED, true);
+ }
+ }
+ if (text_changed || cursor_changed) {
+ OnCaretBoundsChanged();
+ SchedulePaint();
+ }
+}
+
+void Textfield::UpdateCursor() {
+ const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
+ cursor_visible_ = !cursor_visible_ || (caret_blink_ms == 0);
+ RepaintCursor();
+}
+
+void Textfield::RepaintCursor() {
+ gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
+ r.Inset(-1, -1, -1, -1);
+ SchedulePaintInRect(r);
+}
+
+void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) {
+ TRACE_EVENT0("views", "Textfield::PaintTextAndCursor");
+ canvas->Save();
+
+ // Draw placeholder text if needed.
+ gfx::RenderText* render_text = GetRenderText();
+ if (text().empty() && !GetPlaceholderText().empty()) {
+ canvas->DrawStringRect(GetPlaceholderText(), GetFontList(),
+ placeholder_text_color(), render_text->display_rect());
+ }
+
+ // Draw the text, cursor, and selection.
+ render_text->set_cursor_visible(cursor_visible_ && !drop_cursor_visible_ &&
+ !HasSelection());
+ render_text->Draw(canvas);
+
+ // Draw the detached drop cursor that marks where the text will be dropped.
+ if (drop_cursor_visible_)
+ render_text->DrawCursor(canvas, drop_cursor_position_);
+
+ canvas->Restore();
+}
+
+void Textfield::MoveCursorTo(const gfx::Point& point, bool select) {
+ if (model_->MoveCursorTo(point, select))
+ UpdateAfterChange(false, true);
+}
+
+void Textfield::SelectThroughLastDragLocation() {
+ OnBeforeUserAction();
+ model_->MoveCursorTo(last_drag_location_, true);
+ if (aggregated_clicks_ == 1) {
+ model_->SelectWord();
+ // Expand the selection so the initially selected word remains selected.
+ gfx::Range selection = GetRenderText()->selection();
+ const size_t min = std::min(selection.GetMin(),
+ double_click_word_.GetMin());
+ const size_t max = std::max(selection.GetMax(),
+ double_click_word_.GetMax());
+ const bool reversed = selection.is_reversed();
+ selection.set_start(reversed ? max : min);
+ selection.set_end(reversed ? min : max);
+ model_->SelectRange(selection);
+ }
+ UpdateAfterChange(false, true);
+ OnAfterUserAction();
+}
+
+void Textfield::OnCaretBoundsChanged() {
+ if (GetInputMethod())
+ GetInputMethod()->OnCaretBoundsChanged(this);
+ if (touch_selection_controller_)
+ touch_selection_controller_->SelectionChanged();
+}
+
+void Textfield::OnBeforeUserAction() {
+ DCHECK(!performing_user_action_);
+ performing_user_action_ = true;
+ if (controller_)
+ controller_->OnBeforeUserAction(this);
+}
+
+void Textfield::OnAfterUserAction() {
+ if (controller_)
+ controller_->OnAfterUserAction(this);
+ DCHECK(performing_user_action_);
+ performing_user_action_ = false;
+}
+
+bool Textfield::Cut() {
+ if (!read_only() && text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD &&
+ model_->Cut()) {
+ if (controller_)
+ controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ return true;
+ }
+ return false;
+}
+
+bool Textfield::Copy() {
+ if (text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD && model_->Copy()) {
+ if (controller_)
+ controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ return true;
+ }
+ return false;
+}
+
+bool Textfield::Paste() {
+ if (!read_only() && model_->Paste()) {
+ if (controller_)
+ controller_->OnAfterPaste();
+ return true;
+ }
+ return false;
+}
+
+void Textfield::UpdateContextMenu() {
+ if (!context_menu_contents_.get()) {
+ context_menu_contents_.reset(new ui::SimpleMenuModel(this));
+ context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
+ context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
+ context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
+ IDS_APP_SELECT_ALL);
+ if (controller_)
+ controller_->UpdateContextMenu(context_menu_contents_.get());
+ }
+ context_menu_runner_.reset(new MenuRunner(context_menu_contents_.get()));
+}
+
+void Textfield::TrackMouseClicks(const ui::MouseEvent& event) {
+ if (event.IsOnlyLeftMouseButton()) {
+ base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
+ if (time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
+ !ExceededDragThreshold(event.location() - last_click_location_)) {
+ // Upon clicking after a triple click, the count should go back to double
+ // click and alternate between double and triple. This assignment maps
+ // 0 to 1, 1 to 2, 2 to 1.
+ aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
+ } else {
+ aggregated_clicks_ = 0;
+ }
+ last_click_time_ = event.time_stamp();
+ last_click_location_ = event.location();
+ }
+}
+
+bool Textfield::ImeEditingAllowed() const {
+ // Disallow input method editing of password fields.
+ ui::TextInputType t = GetTextInputType();
+ return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD);
+}
+
+void Textfield::RevealPasswordChar(int index) {
+ GetRenderText()->SetObscuredRevealIndex(index);
+ SchedulePaint();
+
+ if (index != -1) {
+ password_reveal_timer_.Start(FROM_HERE, password_reveal_duration_,
+ base::Bind(&Textfield::RevealPasswordChar,
+ weak_ptr_factory_.GetWeakPtr(), -1));
+ }
+}
+
+void Textfield::CreateTouchSelectionControllerAndNotifyIt() {
+ if (!touch_selection_controller_) {
+ touch_selection_controller_.reset(
+ ui::TouchSelectionController::create(this));
+ }
+ if (touch_selection_controller_)
+ touch_selection_controller_->SelectionChanged();
+}
+
+void Textfield::UpdateSelectionClipboard() const {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ if (performing_user_action_ && HasSelection()) {
+ ui::ScopedClipboardWriter(
+ ui::Clipboard::GetForCurrentThread(),
+ ui::CLIPBOARD_TYPE_SELECTION).WriteText(GetSelectedText());
+ if (controller_)
+ controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_SELECTION);
+ }
+#endif
+}
+
+void Textfield::PasteSelectionClipboard(const ui::MouseEvent& event) {
+ DCHECK(event.IsOnlyMiddleMouseButton());
+ DCHECK(!read_only());
+ base::string16 selection_clipboard_text = GetSelectionClipboardText();
+ if (!selection_clipboard_text.empty()) {
+ OnBeforeUserAction();
+ gfx::Range range = GetSelectionModel().selection();
+ gfx::LogicalCursorDirection affinity = GetSelectionModel().caret_affinity();
+ const gfx::SelectionModel mouse =
+ GetRenderText()->FindCursorPosition(event.location());
+ model_->MoveCursorTo(mouse);
+ model_->InsertText(selection_clipboard_text);
+ // Update the new selection range as needed.
+ if (range.GetMin() >= mouse.caret_pos()) {
+ const size_t length = selection_clipboard_text.length();
+ range = gfx::Range(range.start() + length, range.end() + length);
+ }
+ model_->MoveCursorTo(gfx::SelectionModel(range, affinity));
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+ }
}
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index 307e562c20e..e8361774a94 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -12,103 +12,77 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
+#include "base/timer/timer.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/text_input_type.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/base/touch/touch_editing_controller.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/font_list.h"
-#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/range/range.h"
+#include "ui/gfx/selection_model.h"
#include "ui/gfx/text_constants.h"
-#include "ui/views/controls/textfield/native_textfield_wrapper.h"
+#include "ui/views/context_menu_controller.h"
+#include "ui/views/controls/textfield/textfield_model.h"
+#include "ui/views/drag_controller.h"
#include "ui/views/view.h"
-#if !defined(OS_LINUX)
-#include "base/logging.h"
-#endif
-
-namespace gfx {
-class Range;
-class ImageSkia;
-}
-
-namespace ui {
-class TextInputClient;
-} // namespace ui
-
namespace views {
-class ImageView;
+class MenuRunner;
class Painter;
class TextfieldController;
-// This class implements a View that wraps a native text (edit) field.
-class VIEWS_EXPORT Textfield : public View {
+// A views/skia textfield implementation. No platform-specific code is used.
+class VIEWS_EXPORT Textfield : public View,
+ public TextfieldModel::Delegate,
+ public ContextMenuController,
+ public DragController,
+ public ui::TouchEditable,
+ public ui::TextInputClient {
public:
// The textfield's class name.
static const char kViewClassName[];
- enum StyleFlags {
- STYLE_DEFAULT = 0,
- STYLE_OBSCURED = 1 << 0,
- STYLE_LOWERCASE = 1 << 1
- };
-
// Returns the text cursor blink time in milliseconds, or 0 for no blinking.
static size_t GetCaretBlinkMs();
Textfield();
- explicit Textfield(StyleFlags style);
virtual ~Textfield();
- // TextfieldController accessors
- void SetController(TextfieldController* controller);
- TextfieldController* GetController() const;
+ // Set the controller for this textfield.
+ void set_controller(TextfieldController* controller) {
+ controller_ = controller;
+ }
// Gets/Sets whether or not the Textfield is read-only.
bool read_only() const { return read_only_; }
void SetReadOnly(bool read_only);
- // Gets/sets the STYLE_OBSCURED bit, controlling whether characters in this
- // Textfield are displayed as asterisks/bullets.
- bool IsObscured() const;
- void SetObscured(bool obscured);
-
- // Gets/sets the duration to reveal the last typed char when the obscured bit
- // is set. A duration of zero effectively disables the feature. Other values
- // cause the last typed char to be shown for the defined duration. Note this
- // only works with NativeTextfieldViews.
- const base::TimeDelta& obscured_reveal_duration() const {
- return obscured_reveal_duration_;
- }
- void set_obscured_reveal_duration(const base::TimeDelta& duration) {
- obscured_reveal_duration_ = duration;
- }
-
- // Gets/Sets the input type of this textfield.
- ui::TextInputType GetTextInputType() const;
+ // Sets the input type; displays only asterisks for TEXT_INPUT_TYPE_PASSWORD.
void SetTextInputType(ui::TextInputType type);
- // Gets/Sets the text currently displayed in the Textfield.
- const string16& text() const { return text_; }
+ // Gets the text currently displayed in the Textfield.
+ const base::string16& text() const { return model_->text(); }
// Sets the text currently displayed in the Textfield. This doesn't
// change the cursor position if the current cursor is within the
// new text's range, or moves the cursor to the end if the cursor is
// out of the new text's range.
- void SetText(const string16& text);
+ void SetText(const base::string16& new_text);
// Appends the given string to the previously-existing text in the field.
- void AppendText(const string16& text);
+ void AppendText(const base::string16& new_text);
- // Inserts |text| at the current cursor position, replacing any selected text.
- void InsertOrReplaceText(const string16& text);
+ // Inserts |new_text| at the cursor position, replacing any selected text.
+ void InsertOrReplaceText(const base::string16& new_text);
// Returns the text direction.
base::i18n::TextDirection GetTextDirection() const;
// Returns the text that is currently selected.
- string16 GetSelectedText() const;
+ base::string16 GetSelectedText() const;
// Select the entire text range. If |reversed| is true, the range will end at
// the logical beginning of the text; this generally shows the leading portion
@@ -116,56 +90,51 @@ class VIEWS_EXPORT Textfield : public View {
void SelectAll(bool reversed);
// Clears the selection within the edit field and sets the caret to the end.
- void ClearSelection() const;
+ void ClearSelection();
// Checks if there is any selected text.
bool HasSelection() const;
- // Accessor for |style_|.
- StyleFlags style() const { return style_; }
-
- // Gets/Sets the text color to be used when painting the Textfield.
- // Call |UseDefaultTextColor| to restore the default system color.
+ // Gets/sets the text color to be used when painting the Textfield.
+ // Call UseDefaultTextColor() to restore the default system color.
SkColor GetTextColor() const;
void SetTextColor(SkColor color);
void UseDefaultTextColor();
- // Gets/Sets the background color to be used when painting the Textfield.
- // Call |UseDefaultBackgroundColor| to restore the default system color.
+ // Gets/sets the background color to be used when painting the Textfield.
+ // Call UseDefaultBackgroundColor() to restore the default system color.
SkColor GetBackgroundColor() const;
void SetBackgroundColor(SkColor color);
void UseDefaultBackgroundColor();
+ // Gets/sets the selection text color to be used when painting the Textfield.
+ // Call UseDefaultSelectionTextColor() to restore the default system color.
+ SkColor GetSelectionTextColor() const;
+ void SetSelectionTextColor(SkColor color);
+ void UseDefaultSelectionTextColor();
+
+ // Gets/sets the selection background color to be used when painting the
+ // Textfield. Call UseDefaultSelectionBackgroundColor() to restore the default
+ // system color.
+ SkColor GetSelectionBackgroundColor() const;
+ void SetSelectionBackgroundColor(SkColor color);
+ void UseDefaultSelectionBackgroundColor();
+
// Gets/Sets whether or not the cursor is enabled.
bool GetCursorEnabled() const;
void SetCursorEnabled(bool enabled);
// Gets/Sets the fonts used when rendering the text within the Textfield.
- const gfx::FontList& font_list() const { return font_list_; }
+ const gfx::FontList& GetFontList() const;
void SetFontList(const gfx::FontList& font_list);
- const gfx::Font& GetPrimaryFont() const;
- void SetFont(const gfx::Font& font);
-
- // Sets the left and right margin (in pixels) within the text box. On Windows
- // this is accomplished by packing the left and right margin into a single
- // 32 bit number, so the left and right margins are effectively 16 bits.
- void SetHorizontalMargins(int left, int right);
-
- // Sets the top and bottom margins (in pixels) within the textfield.
- // NOTE: in most cases height could be changed instead.
- void SetVerticalMargins(int top, int bottom);
// Sets the default width of the text control. See default_width_in_chars_.
void set_default_width_in_chars(int default_width) {
default_width_in_chars_ = default_width;
}
- // Removes the border from the edit box, giving it a 2D look.
- bool draw_border() const { return draw_border_; }
- void RemoveBorder();
-
// Sets the text to display when empty.
- void set_placeholder_text(const string16& text) {
+ void set_placeholder_text(const base::string16& text) {
placeholder_text_ = text;
}
virtual base::string16 GetPlaceholderText() const;
@@ -175,59 +144,40 @@ class VIEWS_EXPORT Textfield : public View {
placeholder_text_color_ = color;
}
- // Getter for the horizontal margins that were set. Returns false if
- // horizontal margins weren't set.
- bool GetHorizontalMargins(int* left, int* right);
-
- // Getter for the vertical margins that were set. Returns false if vertical
- // margins weren't set.
- bool GetVerticalMargins(int* top, int* bottom);
+ // Get or set the horizontal alignment used for the button from the underlying
+ // RenderText object.
+ gfx::HorizontalAlignment GetHorizontalAlignment() const;
+ void SetHorizontalAlignment(gfx::HorizontalAlignment alignment);
- // Updates all properties on the textfield. This is invoked internally.
- // Users of Textfield never need to invoke this directly.
- void UpdateAllProperties();
-
- // Invoked by the edit control when the value changes. This method set
- // the text_ member variable to the value contained in edit control.
- // This is important because the edit control can be replaced if it has
- // been deleted during a window close.
- void SyncText();
+ // Displays a virtual keyboard or alternate input view if enabled.
+ void ShowImeIfNeeded();
// Returns whether or not an IME is composing text.
bool IsIMEComposing() const;
- // Gets the selected range. This is views-implementation only and
- // has to be called after the wrapper is created.
- // TODO(msw): Return a const reference when NativeTextfieldWin is gone.
- gfx::Range GetSelectedRange() const;
+ // Gets the selected logical text range.
+ const gfx::Range& GetSelectedRange() const;
- // Selects the text given by |range|. This is views-implementation only and
- // has to be called after the wrapper is created.
+ // Selects the specified logical text range.
void SelectRange(const gfx::Range& range);
- // Gets the selection model. This is views-implementation only and
- // has to be called after the wrapper is created.
- // TODO(msw): Return a const reference when NativeTextfieldWin is gone.
- gfx::SelectionModel GetSelectionModel() const;
+ // Gets the text selection model.
+ const gfx::SelectionModel& GetSelectionModel() const;
- // Selects the text given by |sel|. This is views-implementation only and
- // has to be called after the wrapper is created.
+ // Sets the specified text selection model.
void SelectSelectionModel(const gfx::SelectionModel& sel);
- // Returns the current cursor position. This is views-implementation
- // only and has to be called after the wrapper is created.
+ // Returns the current cursor position.
size_t GetCursorPosition() const;
// Set the text color over the entire text or a logical character range.
- // Empty and invalid ranges are ignored. This is views-implementation only and
- // has to be called after the wrapper is created.
+ // Empty and invalid ranges are ignored.
void SetColor(SkColor value);
void ApplyColor(SkColor value, const gfx::Range& range);
// Set various text styles over the entire text or a logical character range.
// The respective |style| is applied if |value| is true, or removed if false.
- // Empty and invalid ranges are ignored. This is views-implementation only and
- // has to be called after the wrapper is created.
+ // Empty and invalid ranges are ignored.
void SetStyle(gfx::TextStyle style, bool value);
void ApplyStyle(gfx::TextStyle style, bool value, const gfx::Range& range);
@@ -235,69 +185,201 @@ class VIEWS_EXPORT Textfield : public View {
void ClearEditHistory();
// Set the accessible name of the text field.
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
// Performs the action associated with the specified command id.
void ExecuteCommand(int command_id);
void SetFocusPainter(scoped_ptr<Painter> focus_painter);
- // Provided only for testing:
- gfx::NativeView GetTestingHandle() const {
- return native_wrapper_ ? native_wrapper_->GetTestingHandle() : NULL;
- }
- NativeTextfieldWrapper* GetNativeWrapperForTesting() const {
- return native_wrapper_;
- }
-
// Returns whether there is a drag operation originating from the textfield.
bool HasTextBeingDragged();
- // Overridden from View:
- virtual void Layout() OVERRIDE;
+ // View overrides:
virtual int GetBaseline() const OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual const char* GetClassName() const OVERRIDE;
+ virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
+ virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual void AboutToRequestFocusFromTabTraversal(bool reverse) OVERRIDE;
- virtual bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) OVERRIDE;
+ virtual bool SkipDefaultKeyEventProcessing(
+ const ui::KeyEvent& event) OVERRIDE;
+ virtual bool GetDropFormats(
+ int* formats,
+ std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
+ virtual bool CanDrop(const ui::OSExchangeData& data) OVERRIDE;
+ virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
+ virtual void OnDragExited() OVERRIDE;
+ virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
+ virtual void OnDragDone() OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
virtual void OnEnabledChanged() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE;
- virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE;
- virtual bool OnMouseDragged(const ui::MouseEvent& e) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
- virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
virtual gfx::Point GetKeyboardContextMenuLocation() OVERRIDE;
+ virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
+
+ // TextfieldModel::Delegate overrides:
+ virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE;
+
+ // ContextMenuController overrides:
+ virtual void ShowContextMenuForView(View* source,
+ const gfx::Point& point,
+ ui::MenuSourceType source_type) OVERRIDE;
+
+ // DragController overrides:
+ virtual void WriteDragDataForView(View* sender,
+ const gfx::Point& press_pt,
+ ui::OSExchangeData* data) OVERRIDE;
+ virtual int GetDragOperationsForView(View* sender,
+ const gfx::Point& p) OVERRIDE;
+ virtual bool CanStartDragForView(View* sender,
+ const gfx::Point& press_pt,
+ const gfx::Point& p) OVERRIDE;
+
+ // ui::TouchEditable overrides:
+ virtual void SelectRect(const gfx::Point& start,
+ const gfx::Point& end) OVERRIDE;
+ virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE;
+ virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE;
+ virtual gfx::Rect GetBounds() OVERRIDE;
+ virtual gfx::NativeView GetNativeView() const OVERRIDE;
+ virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE;
+ virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE;
+ virtual bool DrawsHandles() OVERRIDE;
+ virtual void OpenContextMenu(const gfx::Point& anchor) OVERRIDE;
+ virtual void DestroyTouchSelection() OVERRIDE;
+
+ // ui::SimpleMenuModel::Delegate overrides:
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) OVERRIDE;
+ virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
+
+ // ui::TextInputClient overrides:
+ virtual void SetCompositionText(
+ const ui::CompositionText& composition) OVERRIDE;
+ virtual void ConfirmCompositionText() OVERRIDE;
+ virtual void ClearCompositionText() OVERRIDE;
+ virtual void InsertText(const base::string16& text) OVERRIDE;
+ virtual void InsertChar(base::char16 ch, int flags) OVERRIDE;
+ virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
+ virtual ui::TextInputType GetTextInputType() const OVERRIDE;
+ virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
+ virtual bool CanComposeInline() const OVERRIDE;
+ virtual gfx::Rect GetCaretBounds() const OVERRIDE;
+ virtual bool GetCompositionCharacterBounds(uint32 index,
+ gfx::Rect* rect) const OVERRIDE;
+ virtual bool HasCompositionText() const OVERRIDE;
+ virtual bool GetTextRange(gfx::Range* range) const OVERRIDE;
+ virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE;
+ virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE;
+ virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
+ virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
+ virtual bool GetTextFromRange(const gfx::Range& range,
+ base::string16* text) const OVERRIDE;
+ virtual void OnInputMethodChanged() OVERRIDE;
+ virtual bool ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) OVERRIDE;
+ virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE;
+ virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE;
+ virtual void OnCandidateWindowShown() OVERRIDE;
+ virtual void OnCandidateWindowUpdated() OVERRIDE;
+ virtual void OnCandidateWindowHidden() OVERRIDE;
+ virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE;
+ virtual void ExecuteEditingCommand(int command_id) OVERRIDE;
protected:
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE;
- virtual const char* GetClassName() const OVERRIDE;
+ // Returns the TextfieldModel's text/cursor/selection rendering model.
+ gfx::RenderText* GetRenderText() const;
+
+ gfx::Point last_click_location() const { return last_click_location_; }
- // The object that actually implements the native text field.
- NativeTextfieldWrapper* native_wrapper_;
+ // Get the text from the selection clipboard.
+ virtual base::string16 GetSelectionClipboardText() const;
private:
- // Returns the insets to the rectangle where text is actually painted.
- gfx::Insets GetTextInsets() const;
+ friend class TextfieldTestApi;
// Handles a request to change the value of this text field from software
// using an accessibility API (typically automation software, screen readers
// don't normally use this). Sets the value and clears the selection.
- void AccessibilitySetValue(const string16& new_value);
+ void AccessibilitySetValue(const base::string16& new_value);
- // This is the current listener for events from this Textfield.
- TextfieldController* controller_;
+ // Updates the painted background color.
+ void UpdateBackgroundColor();
+
+ // Does necessary updates when the text and/or cursor position changes.
+ void UpdateAfterChange(bool text_changed, bool cursor_changed);
+
+ // A callback function to periodically update the cursor state.
+ void UpdateCursor();
+
+ // Repaint the cursor.
+ void RepaintCursor();
+
+ void PaintTextAndCursor(gfx::Canvas* canvas);
+
+ // Helper function to call MoveCursorTo on the TextfieldModel.
+ void MoveCursorTo(const gfx::Point& point, bool select);
+
+ // Helper function to update the selection on a mouse drag.
+ void SelectThroughLastDragLocation();
+
+ // Convenience method to notify the InputMethod and TouchSelectionController.
+ void OnCaretBoundsChanged();
+
+ // Convenience method to call TextfieldController::OnBeforeUserAction();
+ void OnBeforeUserAction();
- // The mask of style options for this Textfield.
- StyleFlags style_;
+ // Convenience method to call TextfieldController::OnAfterUserAction();
+ void OnAfterUserAction();
- // The fonts used to render the text in the Textfield.
- gfx::FontList font_list_;
+ // Calls |model_->Cut()| and notifies TextfieldController on success.
+ bool Cut();
- // The text displayed in the Textfield.
- string16 text_;
+ // Calls |model_->Copy()| and notifies TextfieldController on success.
+ bool Copy();
+
+ // Calls |model_->Paste()| and calls TextfieldController::ContentsChanged()
+ // explicitly if paste succeeded.
+ bool Paste();
+
+ // Utility function to prepare the context menu.
+ void UpdateContextMenu();
+
+ // Tracks the mouse clicks for single/double/triple clicks.
+ void TrackMouseClicks(const ui::MouseEvent& event);
+
+ // Returns true if the current text input type allows access by the IME.
+ bool ImeEditingAllowed() const;
+
+ // Reveals the password character at |index| for a set duration.
+ // If |index| is -1, the existing revealed character will be reset.
+ void RevealPasswordChar(int index);
+
+ void CreateTouchSelectionControllerAndNotifyIt();
+
+ // Updates the selection clipboard to any non-empty text selection.
+ void UpdateSelectionClipboard() const;
+
+ // Pastes the selection clipboard for the specified mouse event.
+ void PasteSelectionClipboard(const ui::MouseEvent& event);
+
+ // The text model.
+ scoped_ptr<TextfieldModel> model_;
+
+ // This is the current listener for events from this Textfield.
+ TextfieldController* controller_;
// True if this Textfield cannot accept input and is read-only.
bool read_only_;
@@ -306,48 +388,72 @@ class VIEWS_EXPORT Textfield : public View {
// This will be reported as the "desired size". Defaults to 0.
int default_width_in_chars_;
- // Whether the border is drawn.
- bool draw_border_;
-
- // Text color. Only used if |use_default_text_color_| is false.
- SkColor text_color_;
+ scoped_ptr<Painter> focus_painter_;
- // Should we use the system text color instead of |text_color_|?
+ // Flags indicating whether various system colors should be used, and if not,
+ // what overriding color values should be used instead.
bool use_default_text_color_;
-
- // Background color. Only used if |use_default_background_color_| is false.
- SkColor background_color_;
-
- // Should we use the system background color instead of |background_color_|?
bool use_default_background_color_;
-
- // Holds inner textfield margins.
- gfx::Insets margins_;
-
- // Holds whether margins were set.
- bool horizontal_margins_were_set_;
- bool vertical_margins_were_set_;
+ bool use_default_selection_text_color_;
+ bool use_default_selection_background_color_;
+ SkColor text_color_;
+ SkColor background_color_;
+ SkColor selection_text_color_;
+ SkColor selection_background_color_;
// Text to display when empty.
- string16 placeholder_text_;
+ base::string16 placeholder_text_;
// Placeholder text color.
SkColor placeholder_text_color_;
// The accessible name of the text field.
- string16 accessible_name_;
+ base::string16 accessible_name_;
// The input type of this text field.
ui::TextInputType text_input_type_;
- // The duration to reveal the last typed char for obscured textfields.
- base::TimeDelta obscured_reveal_duration_;
+ // The duration and timer to reveal the last typed password character.
+ base::TimeDelta password_reveal_duration_;
+ base::OneShotTimer<Textfield> password_reveal_timer_;
+
+ // Tracks whether a user action is being performed; i.e. OnBeforeUserAction()
+ // has been called, but OnAfterUserAction() has not yet been called.
+ bool performing_user_action_;
+
+ // True if InputMethod::CancelComposition() should not be called.
+ bool skip_input_method_cancel_composition_;
+
+ // The text editing cursor repaint timer and visibility.
+ base::RepeatingTimer<Textfield> cursor_repaint_timer_;
+ bool cursor_visible_;
+
+ // The drop cursor is a visual cue for where dragged text will be dropped.
+ bool drop_cursor_visible_;
+ gfx::SelectionModel drop_cursor_position_;
+
+ // Is the user potentially dragging and dropping from this view?
+ bool initiating_drag_;
+
+ // A timer and point used to modify the selection when dragging.
+ base::RepeatingTimer<Textfield> drag_selection_timer_;
+ gfx::Point last_drag_location_;
+
+ // State variables used to track double and triple clicks.
+ size_t aggregated_clicks_;
+ base::TimeDelta last_click_time_;
+ gfx::Point last_click_location_;
+ gfx::Range double_click_word_;
+
+ scoped_ptr<ui::TouchSelectionController> touch_selection_controller_;
+
+ // Context menu related members.
+ scoped_ptr<ui::SimpleMenuModel> context_menu_contents_;
+ scoped_ptr<views::MenuRunner> context_menu_runner_;
// Used to bind callback functions to this object.
base::WeakPtrFactory<Textfield> weak_ptr_factory_;
- scoped_ptr<Painter> focus_painter_;
-
DISALLOW_COPY_AND_ASSIGN(Textfield);
};
diff --git a/chromium/ui/views/controls/textfield/textfield_controller.cc b/chromium/ui/views/controls/textfield/textfield_controller.cc
index 8f72be8a1c4..1d90f3c06df 100644
--- a/chromium/ui/views/controls/textfield/textfield_controller.cc
+++ b/chromium/ui/views/controls/textfield/textfield_controller.cc
@@ -23,20 +23,4 @@ int TextfieldController::OnDrop(const ui::OSExchangeData& data) {
return ui::DragDropTypes::DRAG_NONE;
}
-bool TextfieldController::IsCommandIdEnabled(int command_id) const {
- return false;
-}
-
-bool TextfieldController::IsItemForCommandIdDynamic(int command_id) const {
- return false;
-}
-
-string16 TextfieldController::GetLabelForCommandId(int command_id) const {
- return string16();
-}
-
-bool TextfieldController::HandlesCommand(int command_id) const {
- return false;
-}
-
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_controller.h b/chromium/ui/views/controls/textfield/textfield_controller.h
index d72442b41ad..4a01d384f4b 100644
--- a/chromium/ui/views/controls/textfield/textfield_controller.h
+++ b/chromium/ui/views/controls/textfield/textfield_controller.h
@@ -29,7 +29,7 @@ class VIEWS_EXPORT TextfieldController {
// user. It won't be called if the text is changed by calling
// Textfield::SetText() or Textfield::AppendText().
virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) {}
+ const base::string16& new_contents) {}
// This method is called to get notified about keystrokes in the edit.
// Returns true if the message was handled and should not be processed
@@ -52,7 +52,7 @@ class VIEWS_EXPORT TextfieldController {
virtual void OnAfterUserAction(Textfield* sender) {}
// Called after performing a Cut or Copy operation.
- virtual void OnAfterCutOrCopy() {}
+ virtual void OnAfterCutOrCopy(ui::ClipboardType clipboard_type) {}
// Called after performing a Paste operation.
virtual void OnAfterPaste() {}
@@ -79,26 +79,6 @@ class VIEWS_EXPORT TextfieldController {
// Gives the controller a chance to modify the context menu contents.
virtual void UpdateContextMenu(ui::SimpleMenuModel* menu_contents) {}
- // Returns true if the |command_id| should be enabled in the context menu.
- virtual bool IsCommandIdEnabled(int command_id) const;
-
- // Returns true if the item label for the |command_id| is dynamic in the
- // context menu.
- virtual bool IsItemForCommandIdDynamic(int command_id) const;
-
- // Returns the label string for the |coomand_id|.
- virtual string16 GetLabelForCommandId(int command_id) const;
-
- // Returns whether the controller handles the specified command. This is used
- // to handle a command the textfield would normally handle. For example, to
- // have the controller handle |IDS_APP_PASTE| override and return true if
- // |command_id| == |IDS_APP_PASTE|.
- // This is only invoked if the command is enabled.
- virtual bool HandlesCommand(int command_id) const;
-
- // Execute context menu command specified by |command_id|.
- virtual void ExecuteCommand(int command_id, int event_flag) {}
-
protected:
virtual ~TextfieldController() {}
};
diff --git a/chromium/ui/views/controls/textfield/textfield_views_model.cc b/chromium/ui/views/controls/textfield/textfield_model.cc
index 222d0860644..db0dc73b1b0 100644
--- a/chromium/ui/views/controls/textfield/textfield_views_model.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model.cc
@@ -1,69 +1,57 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/controls/textfield/textfield_views_model.h"
+#include "ui/views/controls/textfield/textfield_model.h"
#include <algorithm>
-#include "base/i18n/break_iterator.h"
#include "base/logging.h"
#include "base/stl_util.h"
-#include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
#include "ui/gfx/range/range.h"
-#include "ui/gfx/render_text.h"
-#include "ui/gfx/text_constants.h"
#include "ui/gfx/utf16_indexing.h"
-#include "ui/views/controls/textfield/textfield.h"
namespace views {
namespace internal {
-// An edit object holds enough information/state to undo/redo the
-// change. Two edits are merged when possible, for example, when
-// you type new characters in sequence. |Commit()| can be used to
-// mark an edit as an independent edit and it shouldn't be merged.
-// (For example, when you did undo/redo, or a text is appended via
-// API)
+// Edit holds state information to undo/redo editing changes. Editing operations
+// are merged when possible, like when characters are typed in sequence. Calling
+// Commit() marks an edit as an independent operation that shouldn't be merged.
class Edit {
public:
enum Type {
INSERT_EDIT,
DELETE_EDIT,
- REPLACE_EDIT
+ REPLACE_EDIT,
};
- virtual ~Edit() {
- }
+ virtual ~Edit() {}
// Revert the change made by this edit in |model|.
- void Undo(TextfieldViewsModel* model) {
+ void Undo(TextfieldModel* model) {
model->ModifyText(new_text_start_, new_text_end(),
old_text_, old_text_start_,
old_cursor_pos_);
}
// Apply the change of this edit to the |model|.
- void Redo(TextfieldViewsModel* model) {
+ void Redo(TextfieldModel* model) {
model->ModifyText(old_text_start_, old_text_end(),
new_text_, new_text_start_,
new_cursor_pos_);
}
- // Try to merge the |edit| into this edit. Returns true if merge was
- // successful, or false otherwise. Merged edit will be deleted after
- // redo and should not be reused.
+ // Try to merge the |edit| into this edit and returns true on success. The
+ // merged edit will be deleted after redo and should not be reused.
bool Merge(const Edit* edit) {
// Don't merge if previous edit is DELETE. This happens when a
// user deletes characters then hits return. In this case, the
// delete should be treated as separate edit that can be undone
// and should not be merged with the replace edit.
- if (type_ != DELETE_EDIT && edit->merge_with_previous()) {
+ if (type_ != DELETE_EDIT && edit->force_merge()) {
MergeReplace(edit);
return true;
}
@@ -81,11 +69,11 @@ class Edit {
Edit(Type type,
MergeType merge_type,
size_t old_cursor_pos,
- const string16& old_text,
+ const base::string16& old_text,
size_t old_text_start,
bool delete_backward,
size_t new_cursor_pos,
- const string16& new_text,
+ const base::string16& new_text,
size_t new_text_start)
: type_(type),
merge_type_(merge_type),
@@ -98,8 +86,7 @@ class Edit {
new_text_start_(new_text_start) {
}
- // A template method pattern that provides specific merge
- // implementation for each type of edit.
+ // Each type of edit provides its own specific merge implementation.
virtual bool DoMerge(const Edit* edit) = 0;
Type type() const { return type_; }
@@ -108,9 +95,7 @@ class Edit {
bool mergeable() const { return merge_type_ == MERGEABLE; }
// Should this edit be forcibly merged with the previous edit?
- bool merge_with_previous() const {
- return merge_type_ == MERGE_WITH_PREVIOUS;
- }
+ bool force_merge() const { return merge_type_ == FORCE_MERGE; }
// Returns the end index of the |old_text_|.
size_t old_text_end() const { return old_text_start_ + old_text_.length(); }
@@ -118,14 +103,13 @@ class Edit {
// Returns the end index of the |new_text_|.
size_t new_text_end() const { return new_text_start_ + new_text_.length(); }
- // Merge the replace edit into the current edit. This is a special case to
- // handle an omnibox setting autocomplete string after new character is
- // typed in.
+ // Merge the replace edit into the current edit. This handles the special case
+ // where an omnibox autocomplete string is set after a new character is typed.
void MergeReplace(const Edit* edit) {
CHECK_EQ(REPLACE_EDIT, edit->type_);
CHECK_EQ(0U, edit->old_text_start_);
CHECK_EQ(0U, edit->new_text_start_);
- string16 old_text = edit->old_text_;
+ base::string16 old_text = edit->old_text_;
old_text.erase(new_text_start_, new_text_.length());
old_text.insert(old_text_start_, old_text_);
// SetText() replaces entire text. Set |old_text_| to the entire
@@ -146,7 +130,7 @@ class Edit {
// Old cursor position.
size_t old_cursor_pos_;
// Deleted text by this edit.
- string16 old_text_;
+ base::string16 old_text_;
// The index of |old_text_|.
size_t old_text_start_;
// True if the deletion is made backward.
@@ -154,7 +138,7 @@ class Edit {
// New cursor position.
size_t new_cursor_pos_;
// Added text.
- string16 new_text_;
+ base::string16 new_text_;
// The index of |new_text_|
size_t new_text_start_;
@@ -163,11 +147,11 @@ class Edit {
class InsertEdit : public Edit {
public:
- InsertEdit(bool mergeable, const string16& new_text, size_t at)
+ InsertEdit(bool mergeable, const base::string16& new_text, size_t at)
: Edit(INSERT_EDIT,
mergeable ? MERGEABLE : DO_NOT_MERGE,
at /* old cursor */,
- string16(),
+ base::string16(),
at,
false /* N/A */,
at + new_text.length() /* new cursor */,
@@ -191,12 +175,12 @@ class InsertEdit : public Edit {
class ReplaceEdit : public Edit {
public:
ReplaceEdit(MergeType merge_type,
- const string16& old_text,
+ const base::string16& old_text,
size_t old_cursor_pos,
size_t old_text_start,
bool backward,
size_t new_cursor_pos,
- const string16& new_text,
+ const base::string16& new_text,
size_t new_text_start)
: Edit(REPLACE_EDIT, merge_type,
old_cursor_pos,
@@ -224,7 +208,7 @@ class ReplaceEdit : public Edit {
class DeleteEdit : public Edit {
public:
DeleteEdit(bool mergeable,
- const string16& text,
+ const base::string16& text,
size_t text_start,
bool backward)
: Edit(DELETE_EDIT,
@@ -234,7 +218,7 @@ class DeleteEdit : public Edit {
text_start,
backward,
text_start,
- string16(),
+ base::string16(),
text_start) {
}
@@ -244,16 +228,14 @@ class DeleteEdit : public Edit {
return false;
if (delete_backward_) {
- // backspace can be merged only with backspace at the
- // same position.
+ // backspace can be merged only with backspace at the same position.
if (!edit->delete_backward_ || old_text_start_ != edit->old_text_end())
return false;
old_text_start_ = edit->old_text_start_;
old_text_ = edit->old_text_ + old_text_;
new_cursor_pos_ = edit->new_cursor_pos_;
} else {
- // delete can be merged only with delete at the same
- // position.
+ // delete can be merged only with delete at the same position.
if (edit->delete_backward_ || old_text_start_ != edit->old_text_start_)
return false;
old_text_ += edit->old_text_;
@@ -286,70 +268,61 @@ using internal::InsertEdit;
using internal::ReplaceEdit;
using internal::MergeType;
using internal::DO_NOT_MERGE;
-using internal::MERGE_WITH_PREVIOUS;
+using internal::FORCE_MERGE;
using internal::MERGEABLE;
/////////////////////////////////////////////////////////////////
-// TextfieldViewsModel: public
+// TextfieldModel: public
-TextfieldViewsModel::Delegate::~Delegate() {
-}
+TextfieldModel::Delegate::~Delegate() {}
-TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate)
+TextfieldModel::TextfieldModel(Delegate* delegate)
: delegate_(delegate),
render_text_(gfx::RenderText::CreateInstance()),
current_edit_(edit_history_.end()) {
}
-TextfieldViewsModel::~TextfieldViewsModel() {
+TextfieldModel::~TextfieldModel() {
ClearEditHistory();
ClearComposition();
}
-const string16& TextfieldViewsModel::GetText() const {
- return render_text_->text();
-}
-
-bool TextfieldViewsModel::SetText(const string16& text) {
+bool TextfieldModel::SetText(const base::string16& new_text) {
bool changed = false;
if (HasCompositionText()) {
ConfirmCompositionText();
changed = true;
}
- if (GetText() != text) {
+ if (text() != new_text) {
if (changed) // No need to remember composition.
Undo();
size_t old_cursor = GetCursorPosition();
// SetText moves the cursor to the end.
- size_t new_cursor = text.length();
+ size_t new_cursor = new_text.length();
SelectAll(false);
// If there is a composition text, don't merge with previous edit.
// Otherwise, force merge the edits.
- ExecuteAndRecordReplace(
- changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS,
- old_cursor,
- new_cursor,
- text,
- 0U);
+ ExecuteAndRecordReplace(changed ? DO_NOT_MERGE : FORCE_MERGE,
+ old_cursor, new_cursor, new_text, 0U);
render_text_->SetCursorPosition(new_cursor);
}
ClearSelection();
return changed;
}
-void TextfieldViewsModel::Append(const string16& text) {
+void TextfieldModel::Append(const base::string16& new_text) {
if (HasCompositionText())
ConfirmCompositionText();
size_t save = GetCursorPosition();
MoveCursor(gfx::LINE_BREAK,
render_text_->GetVisualDirectionOfLogicalEnd(),
false);
- InsertText(text);
+ InsertText(new_text);
render_text_->SetCursorPosition(save);
ClearSelection();
}
-bool TextfieldViewsModel::Delete() {
+bool TextfieldModel::Delete() {
if (HasCompositionText()) {
// No undo/redo for composition text.
CancelCompositionText();
@@ -359,7 +332,7 @@ bool TextfieldViewsModel::Delete() {
DeleteSelection();
return true;
}
- if (GetText().length() > GetCursorPosition()) {
+ if (text().length() > GetCursorPosition()) {
size_t cursor_position = GetCursorPosition();
size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme(
cursor_position, gfx::CURSOR_FORWARD);
@@ -370,7 +343,7 @@ bool TextfieldViewsModel::Delete() {
return false;
}
-bool TextfieldViewsModel::Backspace() {
+bool TextfieldModel::Backspace() {
if (HasCompositionText()) {
// No undo/redo for composition text.
CancelCompositionText();
@@ -383,103 +356,104 @@ bool TextfieldViewsModel::Backspace() {
size_t cursor_position = GetCursorPosition();
if (cursor_position > 0) {
// Delete one code point, which may be two UTF-16 words.
- size_t previous_char =
- gfx::UTF16OffsetToIndex(GetText(), cursor_position, -1);
+ size_t previous_char = gfx::UTF16OffsetToIndex(text(), cursor_position, -1);
ExecuteAndRecordDelete(gfx::Range(cursor_position, previous_char), true);
return true;
}
return false;
}
-size_t TextfieldViewsModel::GetCursorPosition() const {
+size_t TextfieldModel::GetCursorPosition() const {
return render_text_->cursor_position();
}
-void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type,
- gfx::VisualCursorDirection direction,
- bool select) {
+void TextfieldModel::MoveCursor(gfx::BreakType break_type,
+ gfx::VisualCursorDirection direction,
+ bool select) {
if (HasCompositionText())
ConfirmCompositionText();
render_text_->MoveCursor(break_type, direction, select);
}
-bool TextfieldViewsModel::MoveCursorTo(const gfx::SelectionModel& model) {
+bool TextfieldModel::MoveCursorTo(const gfx::SelectionModel& cursor) {
if (HasCompositionText()) {
ConfirmCompositionText();
// ConfirmCompositionText() updates cursor position. Need to reflect it in
// the SelectionModel parameter of MoveCursorTo().
- gfx::Range range(render_text_->selection().start(), model.caret_pos());
+ gfx::Range range(render_text_->selection().start(), cursor.caret_pos());
if (!range.is_empty())
return render_text_->SelectRange(range);
return render_text_->MoveCursorTo(
- gfx::SelectionModel(model.caret_pos(), model.caret_affinity()));
+ gfx::SelectionModel(cursor.caret_pos(), cursor.caret_affinity()));
}
- return render_text_->MoveCursorTo(model);
+ return render_text_->MoveCursorTo(cursor);
}
-bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) {
+bool TextfieldModel::MoveCursorTo(const gfx::Point& point, bool select) {
if (HasCompositionText())
ConfirmCompositionText();
- return render_text_->MoveCursorTo(point, select);
+ gfx::SelectionModel cursor = render_text_->FindCursorPosition(point);
+ if (select)
+ cursor.set_selection_start(render_text_->selection().start());
+ return render_text_->MoveCursorTo(cursor);
}
-string16 TextfieldViewsModel::GetSelectedText() const {
- return GetText().substr(render_text_->selection().GetMin(),
- render_text_->selection().length());
+base::string16 TextfieldModel::GetSelectedText() const {
+ return text().substr(render_text_->selection().GetMin(),
+ render_text_->selection().length());
}
-void TextfieldViewsModel::SelectRange(const gfx::Range& range) {
+void TextfieldModel::SelectRange(const gfx::Range& range) {
if (HasCompositionText())
ConfirmCompositionText();
render_text_->SelectRange(range);
}
-void TextfieldViewsModel::SelectSelectionModel(const gfx::SelectionModel& sel) {
+void TextfieldModel::SelectSelectionModel(const gfx::SelectionModel& sel) {
if (HasCompositionText())
ConfirmCompositionText();
render_text_->MoveCursorTo(sel);
}
-void TextfieldViewsModel::SelectAll(bool reversed) {
+void TextfieldModel::SelectAll(bool reversed) {
if (HasCompositionText())
ConfirmCompositionText();
render_text_->SelectAll(reversed);
}
-void TextfieldViewsModel::SelectWord() {
+void TextfieldModel::SelectWord() {
if (HasCompositionText())
ConfirmCompositionText();
render_text_->SelectWord();
}
-void TextfieldViewsModel::ClearSelection() {
+void TextfieldModel::ClearSelection() {
if (HasCompositionText())
ConfirmCompositionText();
render_text_->ClearSelection();
}
-bool TextfieldViewsModel::CanUndo() {
+bool TextfieldModel::CanUndo() {
return edit_history_.size() && current_edit_ != edit_history_.end();
}
-bool TextfieldViewsModel::CanRedo() {
+bool TextfieldModel::CanRedo() {
if (!edit_history_.size())
return false;
- // There is no redo iff the current edit is the last element
- // in the history.
+ // There is no redo iff the current edit is the last element in the history.
EditHistory::iterator iter = current_edit_;
return iter == edit_history_.end() || // at the top.
++iter != edit_history_.end();
}
-bool TextfieldViewsModel::Undo() {
+bool TextfieldModel::Undo() {
if (!CanUndo())
return false;
DCHECK(!HasCompositionText());
- if (HasCompositionText()) // safe guard for release build.
+ if (HasCompositionText())
CancelCompositionText();
- string16 old = GetText();
+ base::string16 old = text();
size_t old_cursor = GetCursorPosition();
(*current_edit_)->Commit();
(*current_edit_)->Undo(this);
@@ -488,27 +462,27 @@ bool TextfieldViewsModel::Undo() {
current_edit_ = edit_history_.end();
else
current_edit_--;
- return old != GetText() || old_cursor != GetCursorPosition();
+ return old != text() || old_cursor != GetCursorPosition();
}
-bool TextfieldViewsModel::Redo() {
+bool TextfieldModel::Redo() {
if (!CanRedo())
return false;
DCHECK(!HasCompositionText());
- if (HasCompositionText()) // safe guard for release build.
+ if (HasCompositionText())
CancelCompositionText();
if (current_edit_ == edit_history_.end())
current_edit_ = edit_history_.begin();
else
current_edit_ ++;
- string16 old = GetText();
+ base::string16 old = text();
size_t old_cursor = GetCursorPosition();
(*current_edit_)->Redo(this);
- return old != GetText() || old_cursor != GetCursorPosition();
+ return old != text() || old_cursor != GetCursorPosition();
}
-bool TextfieldViewsModel::Cut() {
+bool TextfieldModel::Cut() {
if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
ui::ScopedClipboardWriter(
ui::Clipboard::GetForCurrentThread(),
@@ -526,7 +500,7 @@ bool TextfieldViewsModel::Cut() {
return false;
}
-bool TextfieldViewsModel::Copy() {
+bool TextfieldModel::Copy() {
if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
ui::ScopedClipboardWriter(
ui::Clipboard::GetForCurrentThread(),
@@ -536,49 +510,50 @@ bool TextfieldViewsModel::Copy() {
return false;
}
-bool TextfieldViewsModel::Paste() {
- string16 result;
+bool TextfieldModel::Paste() {
+ base::string16 result;
ui::Clipboard::GetForCurrentThread()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE,
&result);
- if (!result.empty()) {
- InsertTextInternal(result, false);
- return true;
- }
- return false;
+ if (result.empty())
+ return false;
+
+ InsertTextInternal(result, false);
+ return true;
}
-bool TextfieldViewsModel::HasSelection() const {
+bool TextfieldModel::HasSelection() const {
return !render_text_->selection().is_empty();
}
-void TextfieldViewsModel::DeleteSelection() {
+void TextfieldModel::DeleteSelection() {
DCHECK(!HasCompositionText());
DCHECK(HasSelection());
ExecuteAndRecordDelete(render_text_->selection(), false);
}
-void TextfieldViewsModel::DeleteSelectionAndInsertTextAt(
- const string16& text, size_t position) {
+void TextfieldModel::DeleteSelectionAndInsertTextAt(
+ const base::string16& new_text,
+ size_t position) {
if (HasCompositionText())
CancelCompositionText();
ExecuteAndRecordReplace(DO_NOT_MERGE,
GetCursorPosition(),
- position + text.length(),
- text,
+ position + new_text.length(),
+ new_text,
position);
}
-string16 TextfieldViewsModel::GetTextFromRange(const gfx::Range& range) const {
- if (range.IsValid() && range.GetMin() < GetText().length())
- return GetText().substr(range.GetMin(), range.length());
- return string16();
+base::string16 TextfieldModel::GetTextFromRange(const gfx::Range& range) const {
+ if (range.IsValid() && range.GetMin() < text().length())
+ return text().substr(range.GetMin(), range.length());
+ return base::string16();
}
-void TextfieldViewsModel::GetTextRange(gfx::Range* range) const {
- *range = gfx::Range(0, GetText().length());
+void TextfieldModel::GetTextRange(gfx::Range* range) const {
+ *range = gfx::Range(0, text().length());
}
-void TextfieldViewsModel::SetCompositionText(
+void TextfieldModel::SetCompositionText(
const ui::CompositionText& composition) {
if (HasCompositionText())
CancelCompositionText();
@@ -589,7 +564,7 @@ void TextfieldViewsModel::SetCompositionText(
return;
size_t cursor = GetCursorPosition();
- string16 new_text = GetText();
+ base::string16 new_text = text();
render_text_->SetText(new_text.insert(cursor, composition.text));
gfx::Range range(cursor, cursor + composition.text.length());
render_text_->SetCompositionRange(range);
@@ -601,8 +576,7 @@ void TextfieldViewsModel::SetCompositionText(
// Because the target clause is more important than the actual selection
// range (or caret position) in the composition here we use a selection-like
// marker instead to show this range.
- // TODO(yukawa, msw): Support thick underline in RenderText and remove
- // this workaround.
+ // TODO(yukawa, msw): Support thick underlines and remove this workaround.
render_text_->SelectRange(gfx::Range(
cursor + emphasized_range.GetMin(),
cursor + emphasized_range.GetMax()));
@@ -615,67 +589,72 @@ void TextfieldViewsModel::SetCompositionText(
}
}
-void TextfieldViewsModel::ConfirmCompositionText() {
+void TextfieldModel::ConfirmCompositionText() {
DCHECK(HasCompositionText());
gfx::Range range = render_text_->GetCompositionRange();
- string16 text = GetText().substr(range.start(), range.length());
+ base::string16 composition = text().substr(range.start(), range.length());
// TODO(oshima): current behavior on ChromeOS is a bit weird and not
// sure exactly how this should work. Find out and fix if necessary.
- AddOrMergeEditHistory(new InsertEdit(false, text, range.start()));
+ AddOrMergeEditHistory(new InsertEdit(false, composition, range.start()));
render_text_->SetCursorPosition(range.end());
ClearComposition();
if (delegate_)
delegate_->OnCompositionTextConfirmedOrCleared();
}
-void TextfieldViewsModel::CancelCompositionText() {
+void TextfieldModel::CancelCompositionText() {
DCHECK(HasCompositionText());
gfx::Range range = render_text_->GetCompositionRange();
ClearComposition();
- string16 new_text = GetText();
+ base::string16 new_text = text();
render_text_->SetText(new_text.erase(range.start(), range.length()));
render_text_->SetCursorPosition(range.start());
if (delegate_)
delegate_->OnCompositionTextConfirmedOrCleared();
}
-void TextfieldViewsModel::ClearComposition() {
+void TextfieldModel::ClearComposition() {
render_text_->SetCompositionRange(gfx::Range::InvalidRange());
}
-void TextfieldViewsModel::GetCompositionTextRange(gfx::Range* range) const {
+void TextfieldModel::GetCompositionTextRange(gfx::Range* range) const {
*range = gfx::Range(render_text_->GetCompositionRange());
}
-bool TextfieldViewsModel::HasCompositionText() const {
+bool TextfieldModel::HasCompositionText() const {
return !render_text_->GetCompositionRange().is_empty();
}
+void TextfieldModel::ClearEditHistory() {
+ STLDeleteElements(&edit_history_);
+ current_edit_ = edit_history_.end();
+}
+
/////////////////////////////////////////////////////////////////
-// TextfieldViewsModel: private
+// TextfieldModel: private
-void TextfieldViewsModel::InsertTextInternal(const string16& text,
- bool mergeable) {
+void TextfieldModel::InsertTextInternal(const base::string16& new_text,
+ bool mergeable) {
if (HasCompositionText()) {
CancelCompositionText();
- ExecuteAndRecordInsert(text, mergeable);
+ ExecuteAndRecordInsert(new_text, mergeable);
} else if (HasSelection()) {
ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE,
- text);
+ new_text);
} else {
- ExecuteAndRecordInsert(text, mergeable);
+ ExecuteAndRecordInsert(new_text, mergeable);
}
}
-void TextfieldViewsModel::ReplaceTextInternal(const string16& text,
- bool mergeable) {
+void TextfieldModel::ReplaceTextInternal(const base::string16& new_text,
+ bool mergeable) {
if (HasCompositionText()) {
CancelCompositionText();
} else if (!HasSelection()) {
size_t cursor = GetCursorPosition();
const gfx::SelectionModel& model = render_text_->selection_model();
// When there is no selection, the default is to replace the next grapheme
- // with |text|. So, need to find the index of next grapheme first.
+ // with |new_text|. So, need to find the index of next grapheme first.
size_t next =
render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD);
if (next == model.caret_pos())
@@ -684,15 +663,10 @@ void TextfieldViewsModel::ReplaceTextInternal(const string16& text,
render_text_->SelectRange(gfx::Range(next, model.caret_pos()));
}
// Edit history is recorded in InsertText.
- InsertTextInternal(text, mergeable);
-}
-
-void TextfieldViewsModel::ClearEditHistory() {
- STLDeleteElements(&edit_history_);
- current_edit_ = edit_history_.end();
+ InsertTextInternal(new_text, mergeable);
}
-void TextfieldViewsModel::ClearRedoHistory() {
+void TextfieldModel::ClearRedoHistory() {
if (edit_history_.begin() == edit_history_.end())
return;
if (current_edit_ == edit_history_.end()) {
@@ -705,20 +679,20 @@ void TextfieldViewsModel::ClearRedoHistory() {
edit_history_.erase(delete_start, edit_history_.end());
}
-void TextfieldViewsModel::ExecuteAndRecordDelete(gfx::Range range,
- bool mergeable) {
+void TextfieldModel::ExecuteAndRecordDelete(gfx::Range range, bool mergeable) {
size_t old_text_start = range.GetMin();
- const string16 text = GetText().substr(old_text_start, range.length());
+ const base::string16 old_text = text().substr(old_text_start, range.length());
bool backward = range.is_reversed();
- Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward);
+ Edit* edit = new DeleteEdit(mergeable, old_text, old_text_start, backward);
bool delete_edit = AddOrMergeEditHistory(edit);
edit->Redo(this);
if (delete_edit)
delete edit;
}
-void TextfieldViewsModel::ExecuteAndRecordReplaceSelection(
- MergeType merge_type, const string16& new_text) {
+void TextfieldModel::ExecuteAndRecordReplaceSelection(
+ MergeType merge_type,
+ const base::string16& new_text) {
size_t new_text_start = render_text_->selection().GetMin();
size_t new_cursor_pos = new_text_start + new_text.length();
ExecuteAndRecordReplace(merge_type,
@@ -728,11 +702,11 @@ void TextfieldViewsModel::ExecuteAndRecordReplaceSelection(
new_text_start);
}
-void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type,
- size_t old_cursor_pos,
- size_t new_cursor_pos,
- const string16& new_text,
- size_t new_text_start) {
+void TextfieldModel::ExecuteAndRecordReplace(MergeType merge_type,
+ size_t old_cursor_pos,
+ size_t new_cursor_pos,
+ const base::string16& new_text,
+ size_t new_text_start) {
size_t old_text_start = render_text_->selection().GetMin();
bool backward = render_text_->selection().is_reversed();
Edit* edit = new ReplaceEdit(merge_type,
@@ -749,28 +723,27 @@ void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type,
delete edit;
}
-void TextfieldViewsModel::ExecuteAndRecordInsert(const string16& text,
- bool mergeable) {
- Edit* edit = new InsertEdit(mergeable, text, GetCursorPosition());
+void TextfieldModel::ExecuteAndRecordInsert(const base::string16& new_text,
+ bool mergeable) {
+ Edit* edit = new InsertEdit(mergeable, new_text, GetCursorPosition());
bool delete_edit = AddOrMergeEditHistory(edit);
edit->Redo(this);
if (delete_edit)
delete edit;
}
-bool TextfieldViewsModel::AddOrMergeEditHistory(Edit* edit) {
+bool TextfieldModel::AddOrMergeEditHistory(Edit* edit) {
ClearRedoHistory();
if (current_edit_ != edit_history_.end() && (*current_edit_)->Merge(edit)) {
- // If a current edit exists and has been merged with a new edit,
- // don't add to the history, and return true to delete |edit| after
- // redo.
+ // If a current edit exists and has been merged with a new edit, don't add
+ // to the history, and return true to delete |edit| after redo.
return true;
}
edit_history_.push_back(edit);
if (current_edit_ == edit_history_.end()) {
- // If there is no redoable edit, this is the 1st edit because
- // RedoHistory has been already deleted.
+ // If there is no redoable edit, this is the 1st edit because RedoHistory
+ // has been already deleted.
DCHECK_EQ(1u, edit_history_.size());
current_edit_ = edit_history_.begin();
} else {
@@ -779,21 +752,20 @@ bool TextfieldViewsModel::AddOrMergeEditHistory(Edit* edit) {
return false;
}
-void TextfieldViewsModel::ModifyText(size_t delete_from,
- size_t delete_to,
- const string16& new_text,
- size_t new_text_insert_at,
- size_t new_cursor_pos) {
+void TextfieldModel::ModifyText(size_t delete_from,
+ size_t delete_to,
+ const base::string16& new_text,
+ size_t new_text_insert_at,
+ size_t new_cursor_pos) {
DCHECK_LE(delete_from, delete_to);
- string16 text = GetText();
+ base::string16 old_text = text();
ClearComposition();
if (delete_from != delete_to)
- render_text_->SetText(text.erase(delete_from, delete_to - delete_from));
+ render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from));
if (!new_text.empty())
- render_text_->SetText(text.insert(new_text_insert_at, new_text));
+ render_text_->SetText(old_text.insert(new_text_insert_at, new_text));
render_text_->SetCursorPosition(new_cursor_pos);
- // TODO(oshima): mac selects the text that is just undone (but gtk doesn't).
- // This looks fine feature and we may want to do the same.
+ // TODO(oshima): Select text that was just undone, like Mac (but not GTK).
}
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_views_model.h b/chromium/ui/views/controls/textfield/textfield_model.h
index 1af734054a9..6ae3398ee46 100644
--- a/chromium/ui/views/controls/textfield/textfield_views_model.h
+++ b/chromium/ui/views/controls/textfield/textfield_model.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
-#define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
+#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_MODEL_H_
+#define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_MODEL_H_
#include <list>
#include <vector>
@@ -11,44 +11,34 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
-#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ime/composition_text.h"
-#include "ui/gfx/rect.h"
#include "ui/gfx/render_text.h"
#include "ui/gfx/text_constants.h"
#include "ui/views/views_export.h"
-namespace gfx {
-class Range;
-class RenderText;
-} // namespace gfx
-
namespace views {
namespace internal {
// Internal Edit class that keeps track of edits for undo/redo.
class Edit;
-// C++ doesn't allow forward decl enum, so let's define here.
+// The types of merge behavior implemented by Edit operations.
enum MergeType {
- // The edit should not be merged with next edit. It still may
- // be merged with an edit with MERGE_WITH_PREVIOUS.
+ // The edit should not usually be merged with next edit.
DO_NOT_MERGE,
- // The edit can be merged with next edit when possible.
+ // The edit should be merged with next edit when possible.
MERGEABLE,
- // Does the edit have to be merged with previous edit?
- // This forces the merge even if the previous edit is marked
- // as DO_NOT_MERGE.
- MERGE_WITH_PREVIOUS,
+ // The edit should be merged with the prior edit, even if marked DO_NOT_MERGE.
+ FORCE_MERGE,
};
} // namespace internal
-// A model that represents a text content for TextfieldViews.
+// A model that represents text content for a views::Textfield.
// It supports editing, selection and cursor manipulation.
-class VIEWS_EXPORT TextfieldViewsModel {
+class VIEWS_EXPORT TextfieldModel {
public:
- // Delegate interface implemented by the textfield view class to provided
+ // Delegate interface implemented by the textfield view class to provide
// additional functionalities required by the model.
class VIEWS_EXPORT Delegate {
public:
@@ -59,47 +49,46 @@ class VIEWS_EXPORT TextfieldViewsModel {
virtual ~Delegate();
};
- explicit TextfieldViewsModel(Delegate* delegate);
- virtual ~TextfieldViewsModel();
+ explicit TextfieldModel(Delegate* delegate);
+ virtual ~TextfieldModel();
// Edit related methods.
- const string16& GetText() const;
- // Sets the text. Returns true if the text has been modified. The
- // current composition text will be confirmed first. Setting
- // the same text will not add edit history because it's not user
- // visible change nor user-initiated change. This allow a client
- // code to set the same text multiple times without worrying about
- // messing edit history.
- bool SetText(const string16& text);
+ const base::string16& text() const { return render_text_->text(); }
+ // Sets the text. Returns true if the text has been modified. The current
+ // composition text will be confirmed first. Setting the same text will not
+ // add edit history because it's not user visible change nor user-initiated
+ // change. This allow a client code to set the same text multiple times
+ // without worrying about messing edit history.
+ bool SetText(const base::string16& new_text);
gfx::RenderText* render_text() { return render_text_.get(); }
- // Inserts given |text| at the current cursor position.
+ // Inserts given |new_text| at the current cursor position.
// The current composition text will be cleared.
- void InsertText(const string16& text) {
- InsertTextInternal(text, false);
+ void InsertText(const base::string16& new_text) {
+ InsertTextInternal(new_text, false);
}
// Inserts a character at the current cursor position.
- void InsertChar(char16 c) {
- InsertTextInternal(string16(&c, 1), true);
+ void InsertChar(base::char16 c) {
+ InsertTextInternal(base::string16(&c, 1), true);
}
// Replaces characters at the current position with characters in given text.
// The current composition text will be cleared.
- void ReplaceText(const string16& text) {
- ReplaceTextInternal(text, false);
+ void ReplaceText(const base::string16& new_text) {
+ ReplaceTextInternal(new_text, false);
}
// Replaces the char at the current position with given character.
- void ReplaceChar(char16 c) {
- ReplaceTextInternal(string16(&c, 1), true);
+ void ReplaceChar(base::char16 c) {
+ ReplaceTextInternal(base::string16(&c, 1), true);
}
// Appends the text.
// The current composition text will be confirmed.
- void Append(const string16& text);
+ void Append(const base::string16& new_text);
// Deletes the first character after the current cursor position (as if, the
// the user has pressed delete key in the textfield). Returns true if
@@ -124,19 +113,17 @@ class VIEWS_EXPORT TextfieldViewsModel {
gfx::VisualCursorDirection direction,
bool select);
- // Moves the selection to the specified selection in |selection|.
- // If there is composition text, it will be confirmed, which will update the
- // selection range, and it overrides the selection_start to which the
- // selection will move to.
- bool MoveCursorTo(const gfx::SelectionModel& selection);
+ // Updates the cursor to the specified selection model. Any composition text
+ // will be confirmed, which may alter the specified selection range start.
+ bool MoveCursorTo(const gfx::SelectionModel& cursor);
- // Helper function to call MoveCursorTo on the TextfieldViewsModel.
+ // Helper function to call MoveCursorTo on the TextfieldModel.
bool MoveCursorTo(const gfx::Point& point, bool select);
- // Selection related method
+ // Selection related methods.
// Returns the selected text.
- string16 GetSelectedText() const;
+ base::string16 GetSelectedText() const;
// The current composition text will be confirmed. The selection starts with
// the range's start position, and ends with the range's end position,
@@ -195,13 +182,12 @@ class VIEWS_EXPORT TextfieldViewsModel {
// composition text.
void DeleteSelection();
- // Deletes the selected text (if any) and insert text at given
- // position.
- void DeleteSelectionAndInsertTextAt(
- const string16& text, size_t position);
+ // Deletes the selected text (if any) and insert text at given position.
+ void DeleteSelectionAndInsertTextAt(const base::string16& new_text,
+ size_t position);
// Retrieves the text content in a given range.
- string16 GetTextFromRange(const gfx::Range& range) const;
+ base::string16 GetTextFromRange(const gfx::Range& range) const;
// Retrieves the range containing all text in the model.
void GetTextRange(gfx::Range* range) const;
@@ -226,30 +212,23 @@ class VIEWS_EXPORT TextfieldViewsModel {
// Returns true if there is composition text.
bool HasCompositionText() const;
+ // Clears all edit history.
+ void ClearEditHistory();
+
private:
- friend class NativeTextfieldViews;
- friend class NativeTextfieldViewsTest;
- friend class TextfieldViewsModelTest;
- friend class UndoRedo_BasicTest;
- friend class UndoRedo_CutCopyPasteTest;
- friend class UndoRedo_ReplaceTest;
friend class internal::Edit;
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_BasicTest);
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest);
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_ReplaceTest);
+ FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_BasicTest);
+ FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_CutCopyPasteTest);
+ FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_ReplaceTest);
- // Insert the given |text|. |mergeable| indicates if this insert
- // operation can be merged to previous edit in the edit history.
- void InsertTextInternal(const string16& text, bool mergeable);
+ // Insert the given |new_text|. |mergeable| indicates if this insert operation
+ // can be merged with previous edits in the history.
+ void InsertTextInternal(const base::string16& new_text, bool mergeable);
- // Replace the current text with the given |text|. |mergeable|
- // indicates if this replace operation can be merged to previous
- // edit in the edit history.
- void ReplaceTextInternal(const string16& text, bool mergeable);
-
- // Clears all edit history.
- void ClearEditHistory();
+ // Replace the current text with the given |new_text|. |mergeable| indicates
+ // if this replace operation can be merged with previous edits in the history.
+ void ReplaceTextInternal(const base::string16& new_text, bool mergeable);
// Clears redo history.
void ClearRedoHistory();
@@ -257,13 +236,13 @@ class VIEWS_EXPORT TextfieldViewsModel {
// Executes and records edit operations.
void ExecuteAndRecordDelete(gfx::Range range, bool mergeable);
void ExecuteAndRecordReplaceSelection(internal::MergeType merge_type,
- const string16& text);
+ const base::string16& new_text);
void ExecuteAndRecordReplace(internal::MergeType merge_type,
size_t old_cursor_pos,
size_t new_cursor_pos,
- const string16& text,
+ const base::string16& new_text,
size_t new_text_start);
- void ExecuteAndRecordInsert(const string16& text, bool mergeable);
+ void ExecuteAndRecordInsert(const base::string16& new_text, bool mergeable);
// Adds or merge |edit| into edit history. Return true if the edit
// has been merged and must be deleted after redo.
@@ -276,14 +255,13 @@ class VIEWS_EXPORT TextfieldViewsModel {
// 3) Move the cursor to |new_cursor_pos|.
void ModifyText(size_t delete_from,
size_t delete_to,
- const string16& new_text,
+ const base::string16& new_text,
size_t new_text_insert_at,
size_t new_cursor_pos);
void ClearComposition();
- // Pointer to a TextfieldViewsModel::Delegate instance, should be provided by
- // the View object.
+ // The TextfieldModel::Delegate instance should be provided by the owner.
Delegate* delegate_;
// The stylized text, cursor, selection, and the visual layout model.
@@ -295,19 +273,20 @@ class VIEWS_EXPORT TextfieldViewsModel {
// An iterator that points to the current edit that can be undone.
// This iterator moves from the |end()|, meaining no edit to undo,
// to the last element (one before |end()|), meaning no edit to redo.
- // There is no edit to undo (== end()) when:
- // 1) in initial state. (nothing to undo)
- // 2) very 1st edit is undone.
- // 3) all edit history is removed.
- // There is no edit to redo (== last element or no element) when:
- // 1) in initial state. (nothing to redo)
- // 2) new edit is added. (redo history is cleared)
- // 3) redone all undone edits.
+ //
+ // There is no edit to undo (== end()) when:
+ // 1) in initial state. (nothing to undo)
+ // 2) very 1st edit is undone.
+ // 3) all edit history is removed.
+ // There is no edit to redo (== last element or no element) when:
+ // 1) in initial state. (nothing to redo)
+ // 2) new edit is added. (redo history is cleared)
+ // 3) redone all undone edits.
EditHistory::iterator current_edit_;
- DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModel);
+ DISALLOW_COPY_AND_ASSIGN(TextfieldModel);
};
} // namespace views
-#endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
+#endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_MODEL_H_
diff --git a/chromium/ui/views/controls/textfield/textfield_views_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
index b23fb10b453..f3947ff0c1c 100644
--- a/chromium/ui/views/controls/textfield/textfield_views_model_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,7 +15,7 @@
#include "ui/gfx/range/range.h"
#include "ui/gfx/render_text.h"
#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/controls/textfield/textfield_views_model.h"
+#include "ui/views/controls/textfield/textfield_model.h"
#include "ui/views/test/test_views_delegate.h"
#include "ui/views/test/views_test_base.h"
@@ -23,7 +23,7 @@
#include "base/win/windows_version.h"
#endif
-#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16)
+#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(base::ASCIIToUTF16(ascii), utf16)
namespace {
@@ -34,7 +34,7 @@ struct WordAndCursor {
size_t cursor;
};
-void MoveCursorTo(views::TextfieldViewsModel& model, size_t pos) {
+void MoveCursorTo(views::TextfieldModel& model, size_t pos) {
model.MoveCursorTo(gfx::SelectionModel(pos, gfx::CURSOR_FORWARD));
}
@@ -42,10 +42,10 @@ void MoveCursorTo(views::TextfieldViewsModel& model, size_t pos) {
namespace views {
-class TextfieldViewsModelTest : public ViewsTestBase,
- public TextfieldViewsModel::Delegate {
+class TextfieldModelTest : public ViewsTestBase,
+ public TextfieldModel::Delegate {
public:
- TextfieldViewsModelTest()
+ TextfieldModelTest()
: ViewsTestBase(),
composition_text_confirmed_or_cleared_(false) {
}
@@ -55,123 +55,116 @@ class TextfieldViewsModelTest : public ViewsTestBase,
}
protected:
- void ResetModel(TextfieldViewsModel* model) const {
- model->SetText(string16());
+ void ResetModel(TextfieldModel* model) const {
+ model->SetText(base::string16());
model->ClearEditHistory();
}
bool composition_text_confirmed_or_cleared_;
private:
- DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModelTest);
+ DISALLOW_COPY_AND_ASSIGN(TextfieldModelTest);
};
-TEST_F(TextfieldViewsModelTest, EditString) {
- TextfieldViewsModel model(NULL);
- // append two strings
- model.Append(ASCIIToUTF16("HILL"));
- EXPECT_STR_EQ("HILL", model.GetText());
- model.Append(ASCIIToUTF16("WORLD"));
- EXPECT_STR_EQ("HILLWORLD", model.GetText());
+TEST_F(TextfieldModelTest, EditString) {
+ TextfieldModel model(NULL);
+ // Append two strings.
+ model.Append(base::ASCIIToUTF16("HILL"));
+ EXPECT_STR_EQ("HILL", model.text());
+ model.Append(base::ASCIIToUTF16("WORLD"));
+ EXPECT_STR_EQ("HILLWORLD", model.text());
- // Insert "E" to make hello
+ // Insert "E" and replace "I" with "L" to make "HELLO".
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
model.InsertChar('E');
- EXPECT_STR_EQ("HEILLWORLD", model.GetText());
- // Replace "I" with "L"
+ EXPECT_STR_EQ("HEILLWORLD", model.text());
model.ReplaceChar('L');
- EXPECT_STR_EQ("HELLLWORLD", model.GetText());
+ EXPECT_STR_EQ("HELLLWORLD", model.text());
model.ReplaceChar('L');
model.ReplaceChar('O');
- EXPECT_STR_EQ("HELLOWORLD", model.GetText());
+ EXPECT_STR_EQ("HELLOWORLD", model.text());
- // Delete 6th char "W", then delete 5th char O"
+ // Delete 6th char "W", then delete 5th char "O".
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("HELLOORLD", model.GetText());
+ EXPECT_STR_EQ("HELLOORLD", model.text());
EXPECT_TRUE(model.Backspace());
EXPECT_EQ(4U, model.GetCursorPosition());
- EXPECT_STR_EQ("HELLORLD", model.GetText());
+ EXPECT_STR_EQ("HELLORLD", model.text());
- // Move the cursor to start. backspace should fail.
+ // Move the cursor to start; backspace should fail.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
EXPECT_FALSE(model.Backspace());
- EXPECT_STR_EQ("HELLORLD", model.GetText());
- // Move the cursor to the end. delete should fail.
+ EXPECT_STR_EQ("HELLORLD", model.text());
+ // Move the cursor to the end; delete should fail, but backspace should work.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_FALSE(model.Delete());
- EXPECT_STR_EQ("HELLORLD", model.GetText());
- // but backspace should work.
+ EXPECT_STR_EQ("HELLORLD", model.text());
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("HELLORL", model.GetText());
+ EXPECT_STR_EQ("HELLORL", model.text());
MoveCursorTo(model, 5);
- model.ReplaceText(ASCIIToUTF16(" WOR"));
- EXPECT_STR_EQ("HELLO WORL", model.GetText());
+ model.ReplaceText(base::ASCIIToUTF16(" WOR"));
+ EXPECT_STR_EQ("HELLO WORL", model.text());
}
-TEST_F(TextfieldViewsModelTest, EditString_SimpleRTL) {
- TextfieldViewsModel model(NULL);
+TEST_F(TextfieldModelTest, EditString_SimpleRTL) {
+ TextfieldModel model(NULL);
// Append two strings.
- model.Append(WideToUTF16(L"\x05d0\x05d1\x05d2"));
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2"), model.GetText());
- model.Append(WideToUTF16(L"\x05e0\x05e1\x05e2"));
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2\x05e0\x05e1\x05e2"),
- model.GetText());
+ model.Append(base::WideToUTF16(L"\x05d0\x05d1\x05d2"));
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05d1\x05d2"), model.text());
+ model.Append(base::WideToUTF16(L"\x05e0\x05e1\x05e2"));
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05d1\x05d2\x05e0\x05e1\x05e2"),
+ model.text());
- // Insert 0x05f0.
+ // Insert "\x05f0".
MoveCursorTo(model, 1);
model.InsertChar(0x05f0);
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05d1\x05d2\x05e0\x05e1\x05e2"),
- model.GetText());
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05f0\x05d1\x05d2\x05e0\x05e1\x05e2"),
+ model.text());
// Replace "\x05d1" with "\x05f1".
model.ReplaceChar(0x05f1);
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05d2\x05e0\x05e1\x05e2"),
- model.GetText());
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05f0\x5f1\x05d2\x05e0\x05e1\x05e2"),
+ model.text());
- // Delete and backspace.
+ // Test Delete and backspace.
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Delete());
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05e0\x05e1\x05e2"),
- model.GetText());
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05f0\x5f1\x05e0\x05e1\x05e2"),
+ model.text());
EXPECT_TRUE(model.Backspace());
EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05e0\x05e1\x05e2"), model.GetText());
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05f0\x05e0\x05e1\x05e2"), model.text());
}
-TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) {
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
+TEST_F(TextfieldModelTest, EditString_ComplexScript) {
+ // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
bool on_windows_xp = false;
#if defined(OS_WIN)
on_windows_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
#endif
- TextfieldViewsModel model(NULL);
+ TextfieldModel model(NULL);
// Append two Hindi strings.
- model.Append(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"));
- EXPECT_EQ(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"),
- model.GetText());
- model.Append(WideToUTF16(L"\x0915\x094d\x092e\x094d"));
- EXPECT_EQ(WideToUTF16(
- L"\x0915\x093f\x0915\x094d\x0915\x0915\x094d\x092e\x094d"),
- model.GetText());
-
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
+ model.Append(base::WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"));
+ EXPECT_EQ(base::WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"), model.text());
+ model.Append(base::WideToUTF16(L"\x0915\x094d\x092e\x094d"));
+ EXPECT_EQ(base::WideToUTF16(
+ L"\x0915\x093f\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), model.text());
+
if (!on_windows_xp) {
- // Check it is not able to place cursor in middle of a grapheme.
+ // Ensure the cursor cannot be placed in the middle of a grapheme.
MoveCursorTo(model, 1);
EXPECT_EQ(0U, model.GetCursorPosition());
MoveCursorTo(model, 2);
EXPECT_EQ(2U, model.GetCursorPosition());
model.InsertChar('a');
- EXPECT_EQ(WideToUTF16(
+ EXPECT_EQ(base::WideToUTF16(
L"\x0915\x093f\x0061\x0915\x094d\x0915\x0915\x094d\x092e\x094d"),
- model.GetText());
+ model.text());
// ReplaceChar will replace the whole grapheme.
model.ReplaceChar('b');
@@ -179,9 +172,9 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) {
// characters turned into empty square due to font regression. So, not able
// to test 2 characters belong to the same grapheme.
#if defined(OS_LINUX)
- EXPECT_EQ(WideToUTF16(
+ EXPECT_EQ(base::WideToUTF16(
L"\x0915\x093f\x0061\x0062\x0915\x0915\x094d\x092e\x094d"),
- model.GetText());
+ model.text());
#endif
EXPECT_EQ(4U, model.GetCursorPosition());
}
@@ -193,22 +186,20 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) {
// to test 2 characters belong to the same grapheme.
#if defined(OS_LINUX)
EXPECT_TRUE(model.Delete());
- EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e\x094d"),
- model.GetText());
- MoveCursorTo(model, model.GetText().length());
- EXPECT_EQ(model.GetText().length(), model.GetCursorPosition());
+ EXPECT_EQ(base::WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e\x094d"),
+ model.text());
+ MoveCursorTo(model, model.text().length());
+ EXPECT_EQ(model.text().length(), model.GetCursorPosition());
EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e"),
- model.GetText());
+ EXPECT_EQ(base::WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e"),
+ model.text());
#endif
// Test cursor position and deletion for Hindi Virama.
- model.SetText(WideToUTF16(L"\x0D38\x0D4D\x0D15\x0D16\x0D2E"));
+ model.SetText(base::WideToUTF16(L"\x0D38\x0D4D\x0D15\x0D16\x0D2E"));
MoveCursorTo(model, 0);
EXPECT_EQ(0U, model.GetCursorPosition());
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
if (!on_windows_xp) {
MoveCursorTo(model, 1);
EXPECT_EQ(0U, model.GetCursorPosition());
@@ -222,44 +213,46 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) {
MoveCursorTo(model, 2);
EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(WideToUTF16(L"\x0D38\x0D15\x0D16\x0D2E"), model.GetText());
+ EXPECT_EQ(base::WideToUTF16(L"\x0D38\x0D15\x0D16\x0D2E"), model.text());
#endif
- model.SetText(WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9"));
+ model.SetText(
+ base::WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9"));
MoveCursorTo(model, 0);
EXPECT_TRUE(model.Delete());
EXPECT_TRUE(model.Delete());
EXPECT_TRUE(model.Delete());
EXPECT_TRUE(model.Delete());
- EXPECT_EQ(WideToUTF16(L""), model.GetText());
+ EXPECT_EQ(base::WideToUTF16(L""), model.text());
// The first 2 characters are not strong directionality characters.
- model.SetText(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC"));
+ model.SetText(
+ base::WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC"));
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"),
- model.GetText());
+ EXPECT_EQ(base::WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"),
+ model.text());
}
-TEST_F(TextfieldViewsModelTest, EmptyString) {
- TextfieldViewsModel model(NULL);
- EXPECT_EQ(string16(), model.GetText());
- EXPECT_EQ(string16(), model.GetSelectedText());
+TEST_F(TextfieldModelTest, EmptyString) {
+ TextfieldModel model(NULL);
+ EXPECT_EQ(base::string16(), model.text());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
EXPECT_EQ(0U, model.GetCursorPosition());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
EXPECT_EQ(0U, model.GetCursorPosition());
- EXPECT_EQ(string16(), model.GetSelectedText());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
EXPECT_FALSE(model.Delete());
EXPECT_FALSE(model.Backspace());
}
-TEST_F(TextfieldViewsModelTest, Selection) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO"));
+TEST_F(TextfieldModelTest, Selection) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO"));
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
EXPECT_STR_EQ("E", model.GetSelectedText());
@@ -271,7 +264,7 @@ TEST_F(TextfieldViewsModelTest, Selection) {
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, true);
EXPECT_STR_EQ("ELLO", model.GetSelectedText());
model.ClearSelection();
- EXPECT_EQ(string16(), model.GetSelectedText());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
// SelectAll(false) selects towards the end.
model.SelectAll(false);
@@ -301,122 +294,123 @@ TEST_F(TextfieldViewsModelTest, Selection) {
EXPECT_EQ(5U, model.GetCursorPosition());
}
-TEST_F(TextfieldViewsModelTest, Selection_BidiWithNonSpacingMarks) {
+TEST_F(TextfieldModelTest, Selection_BidiWithNonSpacingMarks) {
// Selection is a logical operation. And it should work with the arrow
// keys doing visual movements, while the selection is logical between
// the (logical) start and end points. Selection is simply defined as
// the portion of text between the logical positions of the start and end
// caret positions.
- TextfieldViewsModel model(NULL);
+ TextfieldModel model(NULL);
// TODO(xji): temporarily disable in platform Win since the complex script
// characters turned into empty square due to font regression. So, not able
// to test 2 characters belong to the same grapheme.
#if defined(OS_LINUX)
- model.Append(WideToUTF16(
+ model.Append(base::WideToUTF16(
L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"));
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection());
- EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"c"), model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
EXPECT_EQ(gfx::Range(2, 7), model.render_text()->selection());
- EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8"),
+ EXPECT_EQ(base::WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8"),
model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection());
- EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"c"), model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
EXPECT_EQ(gfx::Range(2, 10), model.render_text()->selection());
- EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"d"),
+ EXPECT_EQ(base::WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"d"),
model.GetSelectedText());
model.ClearSelection();
- EXPECT_EQ(string16(), model.GetSelectedText());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
model.SelectAll(false);
- EXPECT_EQ(WideToUTF16(L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"),
- model.GetSelectedText());
+ EXPECT_EQ(
+ base::WideToUTF16(L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"),
+ model.GetSelectedText());
#endif
// In case of "aBc", this test shows how to select "aB" or "Bc", assume 'B' is
// an RTL character.
- model.SetText(WideToUTF16(L"a\x05E9" L"b"));
+ model.SetText(base::WideToUTF16(L"a\x05E9" L"b"));
MoveCursorTo(model, 0);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"a"), model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"a"), model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_EQ(3U, model.GetCursorPosition());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"b"), model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"b"), model.GetSelectedText());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(WideToUTF16(L"a\x05E9"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"a\x05E9"), model.GetSelectedText());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(WideToUTF16(L"\x05E9" L"b"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"\x05E9" L"b"), model.GetSelectedText());
model.ClearSelection();
- EXPECT_EQ(string16(), model.GetSelectedText());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
model.SelectAll(false);
- EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
+ EXPECT_EQ(base::WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
}
-TEST_F(TextfieldViewsModelTest, SelectionAndEdit) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO"));
+TEST_F(TextfieldModelTest, SelectionAndEdit) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO"));
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "EL"
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("HLO", model.GetText());
+ EXPECT_STR_EQ("HLO", model.text());
- model.Append(ASCIIToUTF16("ILL"));
+ model.Append(base::ASCIIToUTF16("ILL"));
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "LO"
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("HILL", model.GetText());
+ EXPECT_STR_EQ("HILL", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "I"
model.InsertChar('E');
- EXPECT_STR_EQ("HELL", model.GetText());
+ EXPECT_STR_EQ("HELL", model.text());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "H"
model.ReplaceChar('B');
- EXPECT_STR_EQ("BELL", model.GetText());
+ EXPECT_STR_EQ("BELL", model.text());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); // "ELL"
model.ReplaceChar('E');
- EXPECT_STR_EQ("BEE", model.GetText());
+ EXPECT_STR_EQ("BEE", model.text());
}
-TEST_F(TextfieldViewsModelTest, Word) {
- TextfieldViewsModel model(NULL);
+TEST_F(TextfieldModelTest, Word) {
+ TextfieldModel model(NULL);
model.Append(
- ASCIIToUTF16("The answer to Life, the Universe, and Everything"));
+ base::ASCIIToUTF16("The answer to Life, the Universe, and Everything"));
model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_EQ(3U, model.GetCursorPosition());
model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
@@ -456,16 +450,16 @@ TEST_F(TextfieldViewsModelTest, Word) {
model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
model.ReplaceChar('4');
- EXPECT_EQ(string16(), model.GetSelectedText());
- EXPECT_STR_EQ("42", model.GetText());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+ EXPECT_STR_EQ("42", model.text());
}
-TEST_F(TextfieldViewsModelTest, SetText) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO"));
+TEST_F(TextfieldModelTest, SetText) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO"));
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.SetText(ASCIIToUTF16("GOODBYE"));
- EXPECT_STR_EQ("GOODBYE", model.GetText());
+ model.SetText(base::ASCIIToUTF16("GOODBYE"));
+ EXPECT_STR_EQ("GOODBYE", model.text());
// SetText move the cursor to the end of the new text.
EXPECT_EQ(7U, model.GetCursorPosition());
model.SelectAll(false);
@@ -473,37 +467,38 @@ TEST_F(TextfieldViewsModelTest, SetText) {
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_EQ(7U, model.GetCursorPosition());
- model.SetText(ASCIIToUTF16("BYE"));
+ model.SetText(base::ASCIIToUTF16("BYE"));
// Setting shorter string moves the cursor to the end of the new string.
EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_EQ(string16(), model.GetSelectedText());
- model.SetText(string16());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+ model.SetText(base::string16());
EXPECT_EQ(0U, model.GetCursorPosition());
}
-TEST_F(TextfieldViewsModelTest, Clipboard) {
+TEST_F(TextfieldModelTest, Clipboard) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
- const string16 initial_clipboard_text = ASCIIToUTF16("initial text");
+ const base::string16 initial_clipboard_text =
+ base::ASCIIToUTF16("initial text");
ui::ScopedClipboardWriter(clipboard, ui::CLIPBOARD_TYPE_COPY_PASTE).
WriteText(initial_clipboard_text);
- string16 clipboard_text;
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
+ base::string16 clipboard_text;
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
// Cut with an empty selection should do nothing.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_FALSE(model.Cut());
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
EXPECT_EQ(initial_clipboard_text, clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.GetText());
+ EXPECT_STR_EQ("HELLO WORLD", model.text());
EXPECT_EQ(11U, model.GetCursorPosition());
// Copy with an empty selection should do nothing.
model.Copy();
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
EXPECT_EQ(initial_clipboard_text, clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.GetText());
+ EXPECT_STR_EQ("HELLO WORLD", model.text());
EXPECT_EQ(11U, model.GetCursorPosition());
// Cut on obscured (password) text should do nothing.
@@ -512,15 +507,15 @@ TEST_F(TextfieldViewsModelTest, Clipboard) {
EXPECT_FALSE(model.Cut());
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
EXPECT_EQ(initial_clipboard_text, clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.GetText());
+ EXPECT_STR_EQ("HELLO WORLD", model.text());
EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText());
- // Copy on obscured text should do nothing.
+ // Copy on obscured (password) text should do nothing.
model.SelectAll(false);
EXPECT_FALSE(model.Copy());
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
EXPECT_EQ(initial_clipboard_text, clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.GetText());
+ EXPECT_STR_EQ("HELLO WORLD", model.text());
EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText());
// Cut with non-empty selection.
@@ -530,7 +525,7 @@ TEST_F(TextfieldViewsModelTest, Clipboard) {
EXPECT_TRUE(model.Cut());
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
EXPECT_STR_EQ("WORLD", clipboard_text);
- EXPECT_STR_EQ("HELLO ", model.GetText());
+ EXPECT_STR_EQ("HELLO ", model.text());
EXPECT_EQ(6U, model.GetCursorPosition());
// Copy with non-empty selection.
@@ -538,69 +533,71 @@ TEST_F(TextfieldViewsModelTest, Clipboard) {
EXPECT_TRUE(model.Copy());
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
EXPECT_STR_EQ("HELLO ", clipboard_text);
- EXPECT_STR_EQ("HELLO ", model.GetText());
+ EXPECT_STR_EQ("HELLO ", model.text());
EXPECT_EQ(6U, model.GetCursorPosition());
// Test that paste works regardless of the obscured bit.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("HELLO HELLO ", model.GetText());
+ EXPECT_STR_EQ("HELLO HELLO ", model.text());
EXPECT_EQ(12U, model.GetCursorPosition());
model.render_text()->SetObscured(true);
EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("HELLO HELLO HELLO ", model.GetText());
+ EXPECT_STR_EQ("HELLO HELLO HELLO ", model.text());
EXPECT_EQ(18U, model.GetCursorPosition());
}
-static void SelectWordTestVerifier(const TextfieldViewsModel& model,
- const string16 &expected_selected_string, size_t expected_cursor_pos) {
+static void SelectWordTestVerifier(
+ const TextfieldModel& model,
+ const base::string16 &expected_selected_string,
+ size_t expected_cursor_pos) {
EXPECT_EQ(expected_selected_string, model.GetSelectedText());
EXPECT_EQ(expected_cursor_pos, model.GetCursorPosition());
}
-TEST_F(TextfieldViewsModelTest, SelectWordTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16(" HELLO !! WO RLD "));
+TEST_F(TextfieldModelTest, SelectWordTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16(" HELLO !! WO RLD "));
// Test when cursor is at the beginning.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" "), 2U);
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 2U);
// Test when cursor is at the beginning of a word.
MoveCursorTo(model, 2);
model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16("HELLO"), 7U);
+ SelectWordTestVerifier(model, base::ASCIIToUTF16("HELLO"), 7U);
// Test when cursor is at the end of a word.
MoveCursorTo(model, 15);
model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U);
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 20U);
// Test when cursor is somewhere in a non-alpha-numeric fragment.
for (size_t cursor_pos = 8; cursor_pos < 13U; cursor_pos++) {
MoveCursorTo(model, cursor_pos);
model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" !! "), 13U);
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" !! "), 13U);
}
// Test when cursor is somewhere in a whitespace fragment.
MoveCursorTo(model, 17);
model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U);
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 20U);
// Test when cursor is at the end.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" "), 24U);
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 24U);
}
// TODO(xji): temporarily disable in platform Win since the complex script
// characters and Chinese characters are turned into empty square due to font
// regression.
#if defined(OS_LINUX)
-TEST_F(TextfieldViewsModelTest, SelectWordTest_MixScripts) {
- TextfieldViewsModel model(NULL);
+TEST_F(TextfieldModelTest, SelectWordTest_MixScripts) {
+ TextfieldModel model(NULL);
std::vector<WordAndCursor> word_and_cursor;
word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2));
word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2));
@@ -617,22 +614,22 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest_MixScripts) {
word_and_cursor.push_back(WordAndCursor(L"\x5929", 14));
// The text consists of Ascii, Hebrew, Hindi with Virama sign, and Chinese.
- model.SetText(WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 "
- L"\x4E2D\x56FD\x82B1\x5929"));
+ model.SetText(base::WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 "
+ L"\x4E2D\x56FD\x82B1\x5929"));
for (size_t i = 0; i < word_and_cursor.size(); ++i) {
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
for (size_t j = 0; j < i; ++j)
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
model.SelectWord();
- SelectWordTestVerifier(model, WideToUTF16(word_and_cursor[i].word),
+ SelectWordTestVerifier(model, base::WideToUTF16(word_and_cursor[i].word),
word_and_cursor[i].cursor);
}
}
#endif
-TEST_F(TextfieldViewsModelTest, RangeTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
+TEST_F(TextfieldModelTest, RangeTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
gfx::Range range = model.render_text()->selection();
EXPECT_TRUE(range.is_empty());
@@ -694,9 +691,9 @@ TEST_F(TextfieldViewsModelTest, RangeTest) {
EXPECT_EQ(0U, range.end());
}
-TEST_F(TextfieldViewsModelTest, SelectRangeTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
+TEST_F(TextfieldModelTest, SelectRangeTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
gfx::Range range(0, 6);
EXPECT_FALSE(range.is_reversed());
model.SelectRange(range);
@@ -738,9 +735,9 @@ TEST_F(TextfieldViewsModelTest, SelectRangeTest) {
EXPECT_TRUE(model.GetSelectedText().empty());
}
-TEST_F(TextfieldViewsModelTest, SelectionTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
+TEST_F(TextfieldModelTest, SelectionTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
gfx::Range selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(0), selection);
@@ -780,9 +777,9 @@ TEST_F(TextfieldViewsModelTest, SelectionTest) {
EXPECT_EQ(gfx::Range(11, 0), selection);
}
-TEST_F(TextfieldViewsModelTest, SelectSelectionModelTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
+TEST_F(TextfieldModelTest, SelectSelectionModelTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(0, 6),
gfx::CURSOR_BACKWARD));
EXPECT_STR_EQ("HELLO ", model.GetSelectedText());
@@ -813,9 +810,9 @@ TEST_F(TextfieldViewsModelTest, SelectSelectionModelTest) {
EXPECT_TRUE(model.GetSelectedText().empty());
}
-TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
- TextfieldViewsModel model(this);
- model.Append(ASCIIToUTF16("1234590"));
+TEST_F(TextfieldModelTest, CompositionTextTest) {
+ TextfieldModel model(this);
+ model.Append(base::ASCIIToUTF16("1234590"));
model.SelectRange(gfx::Range(5, 5));
EXPECT_FALSE(model.HasSelection());
EXPECT_EQ(5U, model.GetCursorPosition());
@@ -825,7 +822,7 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
EXPECT_EQ(gfx::Range(0, 7), range);
ui::CompositionText composition;
- composition.text = ASCIIToUTF16("678");
+ composition.text = base::ASCIIToUTF16("678");
composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false));
// Cursor should be at the end of composition when characters are just typed.
@@ -834,7 +831,7 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
EXPECT_TRUE(model.HasCompositionText());
EXPECT_FALSE(model.HasSelection());
- // Cancel composition
+ // Cancel the composition.
model.CancelCompositionText();
composition_text_confirmed_or_cleared_ = false;
@@ -850,11 +847,11 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
model.GetTextRange(&range);
EXPECT_EQ(10U, range.end());
- EXPECT_STR_EQ("1234567890", model.GetText());
+ EXPECT_STR_EQ("1234567890", model.text());
model.GetCompositionTextRange(&range);
EXPECT_EQ(gfx::Range(5, 8), range);
- // composition text
+ // Check the composition text.
EXPECT_STR_EQ("456", model.GetTextFromRange(gfx::Range(3, 6)));
EXPECT_EQ(gfx::Range(5, 7), model.render_text()->selection());
@@ -867,74 +864,74 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
EXPECT_EQ(5U, model.GetCursorPosition());
model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890", model.GetText());
- EXPECT_TRUE(model.SetText(ASCIIToUTF16("1234567890")));
+ EXPECT_STR_EQ("1234567890", model.text());
+ EXPECT_TRUE(model.SetText(base::ASCIIToUTF16("1234567890")));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890678", model.GetText());
+ EXPECT_STR_EQ("1234567890678", model.text());
- model.InsertText(UTF8ToUTF16("-"));
+ model.InsertText(base::UTF8ToUTF16("-"));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-", model.GetText());
+ EXPECT_STR_EQ("1234567890-", model.text());
EXPECT_FALSE(model.HasCompositionText());
EXPECT_FALSE(model.HasSelection());
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
EXPECT_STR_EQ("-", model.GetSelectedText());
model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890678", model.GetText());
+ EXPECT_STR_EQ("1234567890678", model.text());
- model.ReplaceText(UTF8ToUTF16("-"));
+ model.ReplaceText(base::UTF8ToUTF16("-"));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-", model.GetText());
+ EXPECT_STR_EQ("1234567890-", model.text());
EXPECT_FALSE(model.HasCompositionText());
EXPECT_FALSE(model.HasSelection());
model.SetCompositionText(composition);
- model.Append(UTF8ToUTF16("-"));
+ model.Append(base::UTF8ToUTF16("-"));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.GetText());
+ EXPECT_STR_EQ("1234567890-678-", model.text());
model.SetCompositionText(composition);
model.Delete();
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.GetText());
+ EXPECT_STR_EQ("1234567890-678-", model.text());
model.SetCompositionText(composition);
model.Backspace();
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.GetText());
+ EXPECT_STR_EQ("1234567890-678-", model.text());
- model.SetText(string16());
+ model.SetText(base::string16());
model.SetCompositionText(composition);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
+ EXPECT_STR_EQ("678", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
model.SetCompositionText(composition);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("676788", model.GetText());
+ EXPECT_STR_EQ("676788", model.text());
EXPECT_EQ(6U, model.GetCursorPosition());
model.SetCompositionText(composition);
model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("676788678", model.GetText());
+ EXPECT_STR_EQ("676788678", model.text());
- model.SetText(string16());
+ model.SetText(base::string16());
model.SetCompositionText(composition);
model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
@@ -944,13 +941,13 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678678", model.GetText());
+ EXPECT_STR_EQ("678678", model.text());
model.SetCompositionText(composition);
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
+ EXPECT_STR_EQ("678", model.text());
model.SetCompositionText(composition);
gfx::SelectionModel sel(
@@ -959,25 +956,25 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
model.MoveCursorTo(sel);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678678", model.GetText());
+ EXPECT_STR_EQ("678678", model.text());
model.SetCompositionText(composition);
model.SelectRange(gfx::Range(0, 3));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
+ EXPECT_STR_EQ("678", model.text());
model.SetCompositionText(composition);
model.SelectAll(false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
+ EXPECT_STR_EQ("678", model.text());
model.SetCompositionText(composition);
model.SelectWord();
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
+ EXPECT_STR_EQ("678", model.text());
model.SetCompositionText(composition);
model.ClearSelection();
@@ -989,528 +986,497 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
EXPECT_FALSE(composition_text_confirmed_or_cleared_);
}
-TEST_F(TextfieldViewsModelTest, UndoRedo_BasicTest) {
- TextfieldViewsModel model(NULL);
+TEST_F(TextfieldModelTest, UndoRedo_BasicTest) {
+ TextfieldModel model(NULL);
model.InsertChar('a');
- EXPECT_FALSE(model.Redo()); // nothing to redo
+ EXPECT_FALSE(model.Redo()); // There is nothing to redo.
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_STR_EQ("a", model.text());
// Continuous inserts are treated as one edit.
model.InsertChar('b');
model.InsertChar('c');
- EXPECT_STR_EQ("abc", model.GetText());
+ EXPECT_STR_EQ("abc", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_STR_EQ("a", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
// Undoing further shouldn't change the text.
EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
// Redoing to the latest text.
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_STR_EQ("a", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abc", model.GetText());
+ EXPECT_STR_EQ("abc", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
// Backspace ===============================
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("ab", model.GetText());
+ EXPECT_STR_EQ("ab", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abc", model.GetText());
+ EXPECT_STR_EQ("abc", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ab", model.GetText());
+ EXPECT_STR_EQ("ab", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
// Continous backspaces are treated as one edit.
EXPECT_TRUE(model.Backspace());
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
// Extra backspace shouldn't affect the history.
EXPECT_FALSE(model.Backspace());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ab", model.GetText());
+ EXPECT_STR_EQ("ab", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abc", model.GetText());
+ EXPECT_STR_EQ("abc", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_STR_EQ("a", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
// Clear history
model.ClearEditHistory();
EXPECT_FALSE(model.Undo());
EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_STR_EQ("a", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
// Delete ===============================
- model.SetText(ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
model.ClearEditHistory();
MoveCursorTo(model, 2);
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("ABDE", model.GetText());
+ EXPECT_STR_EQ("ABDE", model.text());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("BDE", model.GetText());
+ EXPECT_STR_EQ("BDE", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABDE", model.GetText());
+ EXPECT_STR_EQ("ABDE", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABDE", model.GetText());
+ EXPECT_STR_EQ("ABDE", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
// Continous deletes are treated as one edit.
EXPECT_TRUE(model.Delete());
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("AB", model.GetText());
+ EXPECT_STR_EQ("AB", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABDE", model.GetText());
+ EXPECT_STR_EQ("ABDE", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("AB", model.GetText());
+ EXPECT_STR_EQ("AB", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
}
-TEST_F(TextfieldViewsModelTest, UndoRedo_SetText) {
+TEST_F(TextfieldModelTest, UndoRedo_SetText) {
// This is to test the undo/redo behavior of omnibox.
- TextfieldViewsModel model(NULL);
+ TextfieldModel model(NULL);
model.InsertChar('w');
- EXPECT_STR_EQ("w", model.GetText());
+ EXPECT_STR_EQ("w", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
- model.SetText(ASCIIToUTF16("www.google.com"));
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
EXPECT_EQ(14U, model.GetCursorPosition());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
model.SelectRange(gfx::Range(14, 1));
model.InsertChar('w');
- EXPECT_STR_EQ("ww", model.GetText());
- model.SetText(ASCIIToUTF16("www.google.com"));
+ EXPECT_STR_EQ("ww", model.text());
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
model.SelectRange(gfx::Range(14, 2));
model.InsertChar('w');
- EXPECT_STR_EQ("www", model.GetText());
- model.SetText(ASCIIToUTF16("www.google.com"));
+ EXPECT_STR_EQ("www", model.text());
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
model.SelectRange(gfx::Range(14, 3));
model.InsertChar('.');
- EXPECT_STR_EQ("www.", model.GetText());
- model.SetText(ASCIIToUTF16("www.google.com"));
+ EXPECT_STR_EQ("www.", model.text());
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
model.SelectRange(gfx::Range(14, 4));
model.InsertChar('y');
- EXPECT_STR_EQ("www.y", model.GetText());
- model.SetText(ASCIIToUTF16("www.youtube.com"));
- EXPECT_STR_EQ("www.youtube.com", model.GetText());
+ EXPECT_STR_EQ("www.y", model.text());
+ model.SetText(base::ASCIIToUTF16("www.youtube.com"));
+ EXPECT_STR_EQ("www.youtube.com", model.text());
EXPECT_EQ(15U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.youtube.com", model.GetText());
+ EXPECT_STR_EQ("www.youtube.com", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
}
-TEST_F(TextfieldViewsModelTest, UndoRedo_BackspaceThenSetText) {
+TEST_F(TextfieldModelTest, UndoRedo_BackspaceThenSetText) {
// This is to test the undo/redo behavior of omnibox.
- TextfieldViewsModel model(NULL);
+ TextfieldModel model(NULL);
model.InsertChar('w');
- EXPECT_STR_EQ("w", model.GetText());
+ EXPECT_STR_EQ("w", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
- model.SetText(ASCIIToUTF16("www.google.com"));
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
EXPECT_EQ(14U, model.GetCursorPosition());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- model.SetText(ASCIIToUTF16("www.google.com")); // Confirm the text.
+ EXPECT_STR_EQ("www.google.com", model.text());
+ model.SetText(base::ASCIIToUTF16("www.google.com")); // Confirm the text.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_EQ(14U, model.GetCursorPosition());
EXPECT_TRUE(model.Backspace());
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("www.google.c", model.GetText());
- // Autocomplete sets the text
- model.SetText(ASCIIToUTF16("www.google.com/search=www.google.c"));
- EXPECT_STR_EQ("www.google.com/search=www.google.c", model.GetText());
+ EXPECT_STR_EQ("www.google.c", model.text());
+ // Autocomplete sets the text.
+ model.SetText(base::ASCIIToUTF16("www.google.com/search=www.google.c"));
+ EXPECT_STR_EQ("www.google.com/search=www.google.c", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.c", model.GetText());
+ EXPECT_STR_EQ("www.google.c", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_STR_EQ("www.google.com", model.text());
}
-TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) {
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("ABCDE"));
- EXPECT_FALSE(model.Redo()); // nothing to redo
- // Cut
+TEST_F(TextfieldModelTest, UndoRedo_CutCopyPasteTest) {
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
+ EXPECT_FALSE(model.Redo()); // There is nothing to redo.
+ // Test Cut.
model.SelectRange(gfx::Range(1, 3));
model.Cut();
- EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_STR_EQ("ADE", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
- EXPECT_FALSE(model.Undo()); // no more undo
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_FALSE(model.Undo()); // There is no more to undo.
+ EXPECT_STR_EQ("", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_STR_EQ("ADE", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_FALSE(model.Redo()); // no more redo
- EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_FALSE(model.Redo()); // There is no more to redo.
+ EXPECT_STR_EQ("ADE", model.text());
model.Paste();
model.Paste();
model.Paste();
- EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
+ EXPECT_STR_EQ("ABCBCBCDE", model.text());
EXPECT_EQ(7U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCDE", model.GetText());
+ EXPECT_STR_EQ("ABCBCDE", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_STR_EQ("ADE", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.GetText()); // Redoing SetText
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
- // Redo
+ // Test Redo.
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_STR_EQ("ADE", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCBCDE", model.GetText());
+ EXPECT_STR_EQ("ABCBCDE", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
+ EXPECT_STR_EQ("ABCBCBCDE", model.text());
EXPECT_EQ(7U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
- // with SelectRange
+ // Test using SelectRange.
model.SelectRange(gfx::Range(1, 3));
EXPECT_TRUE(model.Cut());
- EXPECT_STR_EQ("ABCBCDE", model.GetText());
+ EXPECT_STR_EQ("ABCBCDE", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
model.SelectRange(gfx::Range(1, 1));
EXPECT_FALSE(model.Cut());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("ABCBCDEBC", model.GetText());
+ EXPECT_STR_EQ("ABCBCDEBC", model.text());
EXPECT_EQ(9U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCDE", model.GetText());
+ EXPECT_STR_EQ("ABCBCDE", model.text());
EXPECT_EQ(7U, model.GetCursorPosition());
- // empty cut shouldn't create an edit.
+ // An empty cut shouldn't create an edit.
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
+ EXPECT_STR_EQ("ABCBCBCDE", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
- // Copy
+ // Test Copy.
ResetModel(&model);
- model.SetText(ASCIIToUTF16("12345"));
- EXPECT_STR_EQ("12345", model.GetText());
+ model.SetText(base::ASCIIToUTF16("12345"));
+ EXPECT_STR_EQ("12345", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
model.SelectRange(gfx::Range(1, 3));
- model.Copy(); // Copy "23"
- EXPECT_STR_EQ("12345", model.GetText());
+ model.Copy(); // Copy "23".
+ EXPECT_STR_EQ("12345", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
model.Paste(); // Paste "23" into "23".
- EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_STR_EQ("12345", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
model.Paste();
- EXPECT_STR_EQ("1232345", model.GetText());
+ EXPECT_STR_EQ("1232345", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_STR_EQ("12345", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
- // TODO(oshima): We need to change the return type from bool to enum.
+ // TODO(oshima): Change the return type from bool to enum.
EXPECT_FALSE(model.Undo()); // No text change.
- EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_STR_EQ("12345", model.text());
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_FALSE(model.Undo());
- // Redo
+ // Test Redo.
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_STR_EQ("12345", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("12345", model.GetText()); // For 1st paste
+ EXPECT_STR_EQ("12345", model.text()); // For 1st paste
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("1232345", model.GetText());
+ EXPECT_STR_EQ("1232345", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("1232345", model.GetText());
+ EXPECT_STR_EQ("1232345", model.text());
- // Test using SelectRange
+ // Test using SelectRange.
model.SelectRange(gfx::Range(1, 3));
model.Copy();
- EXPECT_STR_EQ("1232345", model.GetText());
+ EXPECT_STR_EQ("1232345", model.text());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("123234523", model.GetText());
+ EXPECT_STR_EQ("123234523", model.text());
EXPECT_EQ(9U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("1232345", model.GetText());
+ EXPECT_STR_EQ("1232345", model.text());
EXPECT_EQ(7U, model.GetCursorPosition());
}
-TEST_F(TextfieldViewsModelTest, UndoRedo_CursorTest) {
- TextfieldViewsModel model(NULL);
+TEST_F(TextfieldModelTest, UndoRedo_CursorTest) {
+ TextfieldModel model(NULL);
model.InsertChar('a');
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
model.InsertChar('b');
// Moving the cursor shouldn't create a new edit.
- EXPECT_STR_EQ("ab", model.GetText());
+ EXPECT_STR_EQ("ab", model.text());
EXPECT_FALSE(model.Redo());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ab", model.GetText());
+ EXPECT_STR_EQ("ab", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
}
-void RunInsertReplaceTest(TextfieldViewsModel& model) {
+void RunInsertReplaceTest(TextfieldModel& model) {
const bool reverse = model.render_text()->selection().is_reversed();
model.InsertChar('1');
model.InsertChar('2');
model.InsertChar('3');
- EXPECT_STR_EQ("a123d", model.GetText());
+ EXPECT_STR_EQ("a123d", model.text());
EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abcd", model.GetText());
+ EXPECT_STR_EQ("abcd", model.text());
EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abcd", model.GetText());
- EXPECT_EQ(4U, model.GetCursorPosition()); // By SetText
+ EXPECT_STR_EQ("abcd", model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a123d", model.GetText());
+ EXPECT_STR_EQ("a123d", model.text());
EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
}
-void RunOverwriteReplaceTest(TextfieldViewsModel& model) {
+void RunOverwriteReplaceTest(TextfieldModel& model) {
const bool reverse = model.render_text()->selection().is_reversed();
model.ReplaceChar('1');
model.ReplaceChar('2');
model.ReplaceChar('3');
model.ReplaceChar('4');
- EXPECT_STR_EQ("a1234", model.GetText());
+ EXPECT_STR_EQ("a1234", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abcd", model.GetText());
+ EXPECT_STR_EQ("abcd", model.text());
EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abcd", model.GetText());
+ EXPECT_STR_EQ("abcd", model.text());
EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a1234", model.GetText());
+ EXPECT_STR_EQ("a1234", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
}
-TEST_F(TextfieldViewsModelTest, UndoRedo_ReplaceTest) {
- // By Cursor
- {
- SCOPED_TRACE("forward & insert by cursor");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(1, 3));
- RunInsertReplaceTest(model);
- }
- {
- SCOPED_TRACE("backward & insert by cursor");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(3, 1));
- RunInsertReplaceTest(model);
- }
- {
- SCOPED_TRACE("forward & overwrite by cursor");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(1, 3));
- RunOverwriteReplaceTest(model);
- }
- {
- SCOPED_TRACE("backward & overwrite by cursor");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(3, 1));
- RunOverwriteReplaceTest(model);
- }
- // By SelectRange API
+TEST_F(TextfieldModelTest, UndoRedo_ReplaceTest) {
{
- SCOPED_TRACE("forward & insert by SelectRange");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
+ SCOPED_TRACE("Select forwards and insert.");
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("abcd"));
model.SelectRange(gfx::Range(1, 3));
RunInsertReplaceTest(model);
}
{
- SCOPED_TRACE("backward & insert by SelectRange");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
+ SCOPED_TRACE("Select reversed and insert.");
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("abcd"));
model.SelectRange(gfx::Range(3, 1));
RunInsertReplaceTest(model);
}
{
- SCOPED_TRACE("forward & overwrite by SelectRange");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
+ SCOPED_TRACE("Select forwards and overwrite.");
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("abcd"));
model.SelectRange(gfx::Range(1, 3));
RunOverwriteReplaceTest(model);
}
{
- SCOPED_TRACE("backward & overwrite by SelectRange");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
+ SCOPED_TRACE("Select reversed and overwrite.");
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("abcd"));
model.SelectRange(gfx::Range(3, 1));
RunOverwriteReplaceTest(model);
}
}
-TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) {
- TextfieldViewsModel model(NULL);
+TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
+ TextfieldModel model(NULL);
ui::CompositionText composition;
- composition.text = ASCIIToUTF16("abc");
+ composition.text = base::ASCIIToUTF16("abc");
composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false));
composition.selection = gfx::Range(2, 3);
- model.SetText(ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
model.InsertChar('x');
- EXPECT_STR_EQ("ABCDEx", model.GetText());
+ EXPECT_STR_EQ("ABCDEx", model.text());
EXPECT_TRUE(model.Undo()); // set composition should forget undone edit.
model.SetCompositionText(composition);
EXPECT_TRUE(model.HasCompositionText());
EXPECT_TRUE(model.HasSelection());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
- // Accepting composition
+ // Confirm the composition.
model.ConfirmCompositionText();
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
+ EXPECT_STR_EQ("", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
EXPECT_FALSE(model.Redo());
- // Canceling composition
+ // Cancel the composition.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
model.SetCompositionText(composition);
- EXPECT_STR_EQ("abcABCDEabc", model.GetText());
+ EXPECT_STR_EQ("abcABCDEabc", model.text());
model.CancelCompositionText();
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
EXPECT_FALSE(model.Redo());
- // SetText with the same text as the result.
+ // Call SetText with the same text as the result.
ResetModel(&model);
- model.SetText(ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
model.SetCompositionText(composition);
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- model.SetText(ASCIIToUTF16("ABCDEabc"));
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ model.SetText(base::ASCIIToUTF16("ABCDEabc"));
+ EXPECT_STR_EQ("ABCDEabc", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
EXPECT_FALSE(model.Redo());
- // SetText with the different text than the result should not
- // remember composition text.
+ // Call SetText with a different result; the composition should be forgotten.
ResetModel(&model);
- model.SetText(ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
model.SetCompositionText(composition);
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- model.SetText(ASCIIToUTF16("1234"));
- EXPECT_STR_EQ("1234", model.GetText());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ model.SetText(base::ASCIIToUTF16("1234"));
+ EXPECT_STR_EQ("1234", model.text());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_STR_EQ("ABCDE", model.text());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("1234", model.GetText());
+ EXPECT_STR_EQ("1234", model.text());
EXPECT_FALSE(model.Redo());
- // TODO(oshima): We need MockInputMethod to test the behavior with IME.
+ // TODO(oshima): Test the behavior with an IME.
}
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_test_api.cc b/chromium/ui/views/controls/textfield/textfield_test_api.cc
new file mode 100644
index 00000000000..be45d24cc42
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_test_api.cc
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/textfield/textfield_test_api.h"
+
+namespace views {
+
+TextfieldTestApi::TextfieldTestApi(Textfield* textfield)
+ : textfield_(textfield) {
+ DCHECK(textfield);
+}
+
+void TextfieldTestApi::UpdateContextMenu() {
+ textfield_->UpdateContextMenu();
+}
+
+gfx::RenderText* TextfieldTestApi::GetRenderText() const {
+ return textfield_->GetRenderText();
+}
+
+void TextfieldTestApi::CreateTouchSelectionControllerAndNotifyIt() {
+ textfield_->CreateTouchSelectionControllerAndNotifyIt();
+}
+
+void TextfieldTestApi::ResetTouchSelectionController() {
+ textfield_->touch_selection_controller_.reset();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_test_api.h b/chromium/ui/views/controls/textfield/textfield_test_api.h
new file mode 100644
index 00000000000..1af2ffcdf62
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_test_api.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_TEST_API_H_
+#define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_TEST_API_H_
+
+#include "ui/views/controls/textfield/textfield.h"
+
+namespace views {
+
+// Helper class to access internal state of Textfield in tests.
+class TextfieldTestApi {
+ public:
+ explicit TextfieldTestApi(Textfield* textfield);
+
+ void UpdateContextMenu();
+
+ gfx::RenderText* GetRenderText() const;
+
+ void CreateTouchSelectionControllerAndNotifyIt();
+
+ void ResetTouchSelectionController();
+
+ TextfieldModel* model() const { return textfield_->model_.get(); }
+
+ ui::MenuModel* context_menu_contents() const {
+ return textfield_->context_menu_contents_.get();
+ }
+
+ ui::TouchSelectionController* touch_selection_controller() const {
+ return textfield_->touch_selection_controller_.get();
+ }
+
+ private:
+ Textfield* textfield_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldTestApi);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_TEST_API_H_
diff --git a/chromium/ui/views/controls/textfield/native_textfield_views_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index 33196ec3159..8a8f9ace8f5 100644
--- a/chromium/ui/views/controls/textfield/native_textfield_views_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -1,41 +1,35 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/controls/textfield/native_textfield_views.h"
+#include "ui/views/controls/textfield/textfield.h"
#include <set>
#include <string>
#include <vector>
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
#include "base/pickle.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_strings.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_switches.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/render_text.h"
-#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/controls/textfield/textfield_views_model.h"
+#include "ui/views/controls/textfield/textfield_model.h"
+#include "ui/views/controls/textfield/textfield_test_api.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/ime/mock_input_method.h"
#include "ui/views/test/test_views_delegate.h"
#include "ui/views/test/views_test_base.h"
-#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"
@@ -43,20 +37,24 @@
#include "base/win/windows_version.h"
#endif
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h"
+#endif
+
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+using base::WideToUTF16;
+
#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16)
namespace {
-const char16 kHebrewLetterSamekh = 0x05E1;
+const base::char16 kHebrewLetterSamekh = 0x05E1;
// A Textfield wrapper to intercept OnKey[Pressed|Released]() ressults.
class TestTextfield : public views::Textfield {
public:
- explicit TestTextfield(StyleFlags style)
- : Textfield(style),
- key_handled_(false),
- key_received_(false) {
- }
+ TestTextfield() : Textfield(), key_handled_(false), key_received_(false) {}
virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE {
key_received_ = true;
@@ -82,20 +80,6 @@ class TestTextfield : public views::Textfield {
DISALLOW_COPY_AND_ASSIGN(TestTextfield);
};
-// A helper class for use with ui::TextInputClient::GetTextFromRange().
-class GetTextHelper {
- public:
- GetTextHelper() {}
-
- void set_text(const string16& text) { text_ = text; }
- const string16& text() const { return text_; }
-
- private:
- string16 text_;
-
- DISALLOW_COPY_AND_ASSIGN(GetTextHelper);
-};
-
// Convenience to make constructing a GestureEvent simpler.
class GestureEventForTest : public ui::GestureEvent {
public:
@@ -109,24 +93,31 @@ class GestureEventForTest : public ui::GestureEvent {
DISALLOW_COPY_AND_ASSIGN(GestureEventForTest);
};
+base::string16 GetClipboardText(ui::ClipboardType type) {
+ base::string16 text;
+ ui::Clipboard::GetForCurrentThread()->ReadText(type, &text);
+ return text;
+}
+
+void SetClipboardText(ui::ClipboardType type, const std::string& text) {
+ ui::ScopedClipboardWriter(ui::Clipboard::GetForCurrentThread(), type)
+ .WriteText(ASCIIToUTF16(text));
+}
+
} // namespace
namespace views {
-// TODO(oshima): Move tests that are independent of TextfieldViews to
-// textfield_unittests.cc once we move the test utility functions
-// from chrome/browser/automation/ to ui/base/test/.
-class NativeTextfieldViewsTest : public ViewsTestBase,
- public TextfieldController {
+class TextfieldTest : public ViewsTestBase, public TextfieldController {
public:
- NativeTextfieldViewsTest()
+ TextfieldTest()
: widget_(NULL),
textfield_(NULL),
- textfield_view_(NULL),
model_(NULL),
input_method_(NULL),
on_before_user_action_(0),
- on_after_user_action_(0) {
+ on_after_user_action_(0),
+ copied_to_clipboard_(ui::CLIPBOARD_TYPE_LAST) {
}
// ::testing::Test:
@@ -140,21 +131,21 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
ViewsTestBase::TearDown();
}
+ ui::ClipboardType GetAndResetCopiedToClipboard() {
+ ui::ClipboardType clipboard_type = copied_to_clipboard_;
+ copied_to_clipboard_ = ui::CLIPBOARD_TYPE_LAST;
+ return clipboard_type;
+ }
+
// TextfieldController:
virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) OVERRIDE {
+ const base::string16& new_contents) OVERRIDE {
// Paste calls TextfieldController::ContentsChanged() explicitly even if the
// paste action did not change the content. So |new_contents| may match
// |last_contents_|. For more info, see http://crbug.com/79002
last_contents_ = new_contents;
}
- virtual bool HandleKeyEvent(Textfield* sender,
- const ui::KeyEvent& key_event) OVERRIDE {
- // TODO(oshima): figure out how to test the keystroke.
- return false;
- }
-
virtual void OnBeforeUserAction(Textfield* sender) OVERRIDE {
++on_before_user_action_;
}
@@ -163,14 +154,18 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
++on_after_user_action_;
}
- void InitTextfield(Textfield::StyleFlags style) {
- InitTextfields(style, 1);
+ virtual void OnAfterCutOrCopy(ui::ClipboardType clipboard_type) OVERRIDE {
+ copied_to_clipboard_ = clipboard_type;
}
- void InitTextfields(Textfield::StyleFlags style, int count) {
+ void InitTextfield() {
+ InitTextfields(1);
+ }
+
+ void InitTextfields(int count) {
ASSERT_FALSE(textfield_);
- textfield_ = new TestTextfield(style);
- textfield_->SetController(this);
+ textfield_ = new TestTextfield();
+ textfield_->set_controller(this);
widget_ = new Widget();
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.bounds = gfx::Rect(100, 100, 100, 100);
@@ -178,20 +173,17 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
View* container = new View();
widget_->SetContentsView(container);
container->AddChildView(textfield_);
-
- textfield_view_ = static_cast<NativeTextfieldViews*>(
- textfield_->GetNativeWrapperForTesting());
- DCHECK(textfield_view_);
- textfield_view_->SetBoundsRect(params.bounds);
+ textfield_->SetBoundsRect(params.bounds);
textfield_->set_id(1);
+ test_api_.reset(new TextfieldTestApi(textfield_));
for (int i = 1; i < count; i++) {
- Textfield* textfield = new Textfield(style);
+ Textfield* textfield = new Textfield();
container->AddChildView(textfield);
textfield->set_id(i + 1);
}
- model_ = textfield_view_->model_.get();
+ model_ = test_api_->model();
model_->ClearEditHistory();
input_method_ = new MockInputMethod();
@@ -203,12 +195,8 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
}
ui::MenuModel* GetContextMenuModel() {
- textfield_view_->UpdateContextMenu();
- return textfield_view_->context_menu_contents_.get();
- }
-
- ui::TouchSelectionController* GetTouchSelectionController() {
- return textfield_view_->touch_selection_controller_.get();
+ test_api_->UpdateContextMenu();
+ return test_api_->context_menu_contents();
}
protected:
@@ -233,7 +221,7 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
SendKeyEvent(key_code, false, false);
}
- void SendKeyEvent(char16 ch) {
+ void SendKeyEvent(base::char16 ch) {
if (ch < 0x80) {
ui::KeyboardCode code =
ch == ' ' ? ui::VKEY_SPACE :
@@ -246,73 +234,51 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
}
}
- string16 GetClipboardText() const {
- string16 text;
- ui::Clipboard::GetForCurrentThread()->
- ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text);
- return text;
- }
-
- void SetClipboardText(const std::string& text) {
- ui::ScopedClipboardWriter clipboard_writer(
- ui::Clipboard::GetForCurrentThread(),
- ui::CLIPBOARD_TYPE_COPY_PASTE);
- clipboard_writer.WriteText(ASCIIToUTF16(text));
- }
-
View* GetFocusedView() {
return widget_->GetFocusManager()->GetFocusedView();
}
int GetCursorPositionX(int cursor_pos) {
- gfx::RenderText* render_text = textfield_view_->GetRenderText();
- return render_text->GetCursorBounds(
+ return test_api_->GetRenderText()->GetCursorBounds(
gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x();
}
// Get the current cursor bounds.
gfx::Rect GetCursorBounds() {
- gfx::RenderText* render_text = textfield_view_->GetRenderText();
- gfx::Rect bounds = render_text->GetUpdatedCursorBounds();
- return bounds;
+ return test_api_->GetRenderText()->GetUpdatedCursorBounds();
}
// Get the cursor bounds of |sel|.
gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) {
- gfx::RenderText* render_text = textfield_view_->GetRenderText();
- gfx::Rect bounds = render_text->GetCursorBounds(sel, true);
- return bounds;
+ return test_api_->GetRenderText()->GetCursorBounds(sel, true);
}
gfx::Rect GetDisplayRect() {
- return textfield_view_->GetRenderText()->display_rect();
+ return test_api_->GetRenderText()->display_rect();
}
// Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and
// y-axis is in the middle of |bound|'s vertical range.
void MouseClick(const gfx::Rect bound, int x_offset) {
- gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2);
+ gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2);
ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click);
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMouseReleased(release);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release);
}
// This is to avoid double/triple click.
void NonClientMouseClick() {
ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT);
- textfield_view_->OnMousePressed(click);
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click);
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT);
- textfield_view_->OnMouseReleased(release);
- }
-
- // Wrap for visibility in test classes.
- ui::TextInputType GetTextInputType() {
- return textfield_view_->GetTextInputType();
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release);
}
void VerifyTextfieldContextMenuContents(bool textfield_has_selection,
@@ -322,7 +288,8 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
EXPECT_TRUE(menu->IsEnabledAt(1 /* Separator */));
EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(2 /* CUT */));
EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(3 /* COPY */));
- EXPECT_NE(GetClipboardText().empty(), menu->IsEnabledAt(4 /* PASTE */));
+ EXPECT_NE(GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE).empty(),
+ menu->IsEnabledAt(4 /* PASTE */));
EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(5 /* DELETE */));
EXPECT_TRUE(menu->IsEnabledAt(6 /* Separator */));
EXPECT_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */));
@@ -332,11 +299,11 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
Widget* widget_;
TestTextfield* textfield_;
- NativeTextfieldViews* textfield_view_;
- TextfieldViewsModel* model_;
+ scoped_ptr<TextfieldTestApi> test_api_;
+ TextfieldModel* model_;
// The string from Controller::ContentsChanged callback.
- string16 last_contents_;
+ base::string16 last_contents_;
// For testing input method related behaviors.
MockInputMethod* input_method_;
@@ -348,112 +315,36 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
int on_after_user_action_;
private:
- DISALLOW_COPY_AND_ASSIGN(NativeTextfieldViewsTest);
+ ui::ClipboardType copied_to_clipboard_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldTest);
};
-TEST_F(NativeTextfieldViewsTest, ModelChangesTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, ModelChangesTest) {
+ InitTextfield();
// TextfieldController::ContentsChanged() shouldn't be called when changing
// text programmatically.
last_contents_.clear();
textfield_->SetText(ASCIIToUTF16("this is"));
- EXPECT_STR_EQ("this is", model_->GetText());
+ EXPECT_STR_EQ("this is", model_->text());
EXPECT_STR_EQ("this is", textfield_->text());
EXPECT_TRUE(last_contents_.empty());
textfield_->AppendText(ASCIIToUTF16(" a test"));
- EXPECT_STR_EQ("this is a test", model_->GetText());
+ EXPECT_STR_EQ("this is a test", model_->text());
EXPECT_STR_EQ("this is a test", textfield_->text());
EXPECT_TRUE(last_contents_.empty());
- EXPECT_EQ(string16(), textfield_->GetSelectedText());
+ EXPECT_EQ(base::string16(), textfield_->GetSelectedText());
textfield_->SelectAll(false);
EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText());
EXPECT_TRUE(last_contents_.empty());
}
-TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCase) {
- // Check if |model_|'s text is properly lowercased for STYLE_LOWERCASE.
- InitTextfield(Textfield::STYLE_LOWERCASE);
- EXPECT_EQ(0U, textfield_->GetCursorPosition());
-
- last_contents_.clear();
- textfield_->SetText(ASCIIToUTF16("THIS IS"));
- EXPECT_EQ(7U, textfield_->GetCursorPosition());
-
- EXPECT_STR_EQ("this is", model_->GetText());
- EXPECT_STR_EQ("THIS IS", textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-
- textfield_->AppendText(ASCIIToUTF16(" A TEST"));
- EXPECT_EQ(7U, textfield_->GetCursorPosition());
- EXPECT_STR_EQ("this is a test", model_->GetText());
- EXPECT_STR_EQ("THIS IS A TEST", textfield_->text());
-
- EXPECT_TRUE(last_contents_.empty());
-}
-
-TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseI18n) {
- // Check if lower case conversion works for non-ASCII characters.
- InitTextfield(Textfield::STYLE_LOWERCASE);
- EXPECT_EQ(0U, textfield_->GetCursorPosition());
-
- last_contents_.clear();
- // Zenkaku Japanese "ABCabc"
- textfield_->SetText(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"));
- EXPECT_EQ(6U, textfield_->GetCursorPosition());
- // Zenkaku Japanese "abcabc"
- EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43"),
- model_->GetText());
- // Zenkaku Japanese "ABCabc"
- EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"),
- textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-
- // Zenkaku Japanese "XYZxyz"
- textfield_->AppendText(WideToUTF16(L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A"));
- EXPECT_EQ(6U, textfield_->GetCursorPosition());
- // Zenkaku Japanese "abcabcxyzxyz"
- EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43"
- L"\xFF58\xFF59\xFF5A\xFF58\xFF59\xFF5A"),
- model_->GetText());
- // Zenkaku Japanese "ABCabcXYZxyz"
- EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"
- L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A"),
- textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-}
-
-TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseWithLocale) {
- // Check if lower case conversion honors locale properly.
- std::string locale = l10n_util::GetApplicationLocale("");
- base::i18n::SetICUDefaultLocale("tr");
-
- InitTextfield(Textfield::STYLE_LOWERCASE);
- EXPECT_EQ(0U, textfield_->GetCursorPosition());
-
- last_contents_.clear();
- // Turkish 'I' should be converted to dotless 'i' (U+0131).
- textfield_->SetText(WideToUTF16(L"I"));
- EXPECT_EQ(1U, textfield_->GetCursorPosition());
- EXPECT_EQ(WideToUTF16(L"\x0131"), model_->GetText());
- EXPECT_EQ(WideToUTF16(L"I"), textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-
- base::i18n::SetICUDefaultLocale(locale);
-
- // On default (en) locale, 'I' should be converted to 'i'.
- textfield_->SetText(WideToUTF16(L"I"));
- EXPECT_EQ(1U, textfield_->GetCursorPosition());
- EXPECT_EQ(WideToUTF16(L"i"), model_->GetText());
- EXPECT_EQ(WideToUTF16(L"I"), textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-}
-
-TEST_F(NativeTextfieldViewsTest, KeyTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, KeyTest) {
+ InitTextfield();
// Event flags: key, alt, shift, ctrl, caps-lock.
SendKeyEvent(ui::VKEY_T, false, true, false, false);
SendKeyEvent(ui::VKEY_E, false, false, false, false);
@@ -466,9 +357,9 @@ TEST_F(NativeTextfieldViewsTest, KeyTest) {
EXPECT_STR_EQ("TexT!1!1", textfield_->text());
}
-TEST_F(NativeTextfieldViewsTest, ControlAndSelectTest) {
+TEST_F(TextfieldTest, ControlAndSelectTest) {
// Insert a test string in a textfield.
- InitTextfield(Textfield::STYLE_DEFAULT);
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("one two three"));
SendKeyEvent(ui::VKEY_HOME, false /* shift */, false /* control */);
SendKeyEvent(ui::VKEY_RIGHT, true, false);
@@ -501,9 +392,9 @@ TEST_F(NativeTextfieldViewsTest, ControlAndSelectTest) {
EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText());
}
-TEST_F(NativeTextfieldViewsTest, InsertionDeletionTest) {
+TEST_F(TextfieldTest, InsertionDeletionTest) {
// Insert a test string in a textfield.
- InitTextfield(Textfield::STYLE_DEFAULT);
+ InitTextfield();
for (size_t i = 0; i < 10; i++)
SendKeyEvent(static_cast<ui::KeyboardCode>(ui::VKEY_A + i));
EXPECT_STR_EQ("abcdefghij", textfield_->text());
@@ -528,13 +419,13 @@ TEST_F(NativeTextfieldViewsTest, InsertionDeletionTest) {
SendKeyEvent(ui::VKEY_BACK, false, false, true, false);
EXPECT_STR_EQ("one two three ", textfield_->text());
- // Delete text preceeding the cursor in chromeos, do nothing in windows.
+ // Delete to a line break on Linux and ChromeOS, to a word break on Windows.
SendKeyEvent(ui::VKEY_LEFT, false, false, true, false);
SendKeyEvent(ui::VKEY_BACK, false, true, true, false);
-#if defined(OS_WIN)
- EXPECT_STR_EQ("one two three ", textfield_->text());
-#else
+#if defined(OS_LINUX)
EXPECT_STR_EQ("three ", textfield_->text());
+#else
+ EXPECT_STR_EQ("one three ", textfield_->text());
#endif
// Delete the next word from cursor.
@@ -543,21 +434,22 @@ TEST_F(NativeTextfieldViewsTest, InsertionDeletionTest) {
SendKeyEvent(ui::VKEY_DELETE, false, false, true, false);
EXPECT_STR_EQ(" two three four", textfield_->text());
- // Delete text following the cursor in chromeos, do nothing in windows.
+ // Delete to a line break on Linux and ChromeOS, to a word break on Windows.
SendKeyEvent(ui::VKEY_RIGHT, false, false, true, false);
SendKeyEvent(ui::VKEY_DELETE, false, true, true, false);
-#if defined(OS_WIN)
- EXPECT_STR_EQ(" two three four", textfield_->text());
-#else
+#if defined(OS_LINUX)
EXPECT_STR_EQ(" two", textfield_->text());
+#else
+ EXPECT_STR_EQ(" two four", textfield_->text());
#endif
}
-TEST_F(NativeTextfieldViewsTest, PasswordTest) {
- InitTextfield(Textfield::STYLE_OBSCURED);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType());
+TEST_F(TextfieldTest, PasswordTest) {
+ InitTextfield();
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
EXPECT_TRUE(textfield_->enabled());
- EXPECT_TRUE(textfield_->focusable());
+ EXPECT_TRUE(textfield_->IsFocusable());
last_contents_.clear();
textfield_->SetText(ASCIIToUTF16("password"));
@@ -565,143 +457,154 @@ TEST_F(NativeTextfieldViewsTest, PasswordTest) {
EXPECT_STR_EQ("password", textfield_->text());
EXPECT_TRUE(last_contents_.empty());
model_->SelectAll(false);
- SetClipboardText("foo");
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "foo");
// Cut and copy should be disabled.
- EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_view_->ExecuteCommand(IDS_APP_CUT, 0);
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
+ textfield_->ExecuteCommand(IDS_APP_CUT, 0);
SendKeyEvent(ui::VKEY_X, false, true);
- EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_view_->ExecuteCommand(IDS_APP_COPY, 0);
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
+ textfield_->ExecuteCommand(IDS_APP_COPY, 0);
SendKeyEvent(ui::VKEY_C, false, true);
SendKeyEvent(ui::VKEY_INSERT, false, true);
- EXPECT_STR_EQ("foo", string16(GetClipboardText()));
+ EXPECT_STR_EQ("foo", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("password", textfield_->text());
// [Shift]+[Delete] should just delete without copying text to the clipboard.
textfield_->SelectAll(false);
SendKeyEvent(ui::VKEY_DELETE, true, false);
// Paste should work normally.
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0);
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
+ textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
SendKeyEvent(ui::VKEY_V, false, true);
SendKeyEvent(ui::VKEY_INSERT, true, false);
- EXPECT_STR_EQ("foo", string16(GetClipboardText()));
+ EXPECT_STR_EQ("foo", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("foofoofoo", textfield_->text());
}
-TEST_F(NativeTextfieldViewsTest, InputTypeSetsObscured) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // Defaults to TEXT
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType());
-
- // Setting to TEXT_INPUT_TYPE_PASSWORD also sets obscured state of textfield.
- textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType());
- EXPECT_TRUE(textfield_->IsObscured());
-}
-
-TEST_F(NativeTextfieldViewsTest, ObscuredSetsInputType) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // Defaults to TEXT
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType());
-
- textfield_->SetObscured(true);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType());
-
- textfield_->SetObscured(false);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType());
-}
-
-TEST_F(NativeTextfieldViewsTest, TextInputType) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, TextInputType) {
+ InitTextfield();
// Defaults to TEXT
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType());
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, textfield_->GetTextInputType());
// And can be set.
textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_URL);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, GetTextInputType());
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, textfield_->GetTextInputType());
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
// Readonly textfields have type NONE
textfield_->SetReadOnly(true);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType());
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, textfield_->GetTextInputType());
textfield_->SetReadOnly(false);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, GetTextInputType());
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
// As do disabled textfields
textfield_->SetEnabled(false);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType());
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, textfield_->GetTextInputType());
+
+ textfield_->SetEnabled(true);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
}
-TEST_F(NativeTextfieldViewsTest, OnKeyPressReturnValueTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, OnKeyPress) {
+ InitTextfield();
- // Character keys will be handled by input method.
+ // Character keys are handled by the input method.
SendKeyEvent(ui::VKEY_A);
EXPECT_TRUE(textfield_->key_received());
EXPECT_FALSE(textfield_->key_handled());
textfield_->clear();
- // Home will be handled.
- SendKeyEvent(ui::VKEY_HOME);
+ // Arrow keys and home/end are handled by the textfield.
+ SendKeyEvent(ui::VKEY_LEFT);
EXPECT_TRUE(textfield_->key_received());
EXPECT_TRUE(textfield_->key_handled());
textfield_->clear();
- // F24, up/down key won't be handled.
- SendKeyEvent(ui::VKEY_F24);
+ SendKeyEvent(ui::VKEY_RIGHT);
EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
+ EXPECT_TRUE(textfield_->key_handled());
textfield_->clear();
- SendKeyEvent(ui::VKEY_UP);
+ SendKeyEvent(ui::VKEY_HOME);
EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
+ EXPECT_TRUE(textfield_->key_handled());
textfield_->clear();
- SendKeyEvent(ui::VKEY_DOWN);
+ SendKeyEvent(ui::VKEY_END);
EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
+ EXPECT_TRUE(textfield_->key_handled());
textfield_->clear();
- // Empty Textfield does not handle left/right.
- textfield_->SetText(string16());
- SendKeyEvent(ui::VKEY_LEFT);
+ // F24, up/down key won't be handled.
+ SendKeyEvent(ui::VKEY_F24);
EXPECT_TRUE(textfield_->key_received());
EXPECT_FALSE(textfield_->key_handled());
textfield_->clear();
- SendKeyEvent(ui::VKEY_RIGHT);
+ SendKeyEvent(ui::VKEY_UP);
EXPECT_TRUE(textfield_->key_received());
EXPECT_FALSE(textfield_->key_handled());
textfield_->clear();
- // Add a char. Right key should not be handled when cursor is at the end.
- SendKeyEvent(ui::VKEY_B);
- SendKeyEvent(ui::VKEY_RIGHT);
+ SendKeyEvent(ui::VKEY_DOWN);
EXPECT_TRUE(textfield_->key_received());
EXPECT_FALSE(textfield_->key_handled());
textfield_->clear();
+}
- // First left key is handled to move cursor left to the beginning.
- SendKeyEvent(ui::VKEY_LEFT);
+// Tests that default key bindings are handled even with a delegate installed.
+TEST_F(TextfieldTest, OnKeyPressBinding) {
+ InitTextfield();
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Install a TextEditKeyBindingsDelegateAuraLinux that does nothing.
+ class TestDelegate : public ui::TextEditKeyBindingsDelegateAuraLinux {
+ public:
+ TestDelegate() {}
+ virtual ~TestDelegate() {}
+
+ virtual bool MatchEvent(
+ const ui::Event& event,
+ std::vector<ui::TextEditCommandAuraLinux>* commands) OVERRIDE {
+ return false;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+ };
+
+ TestDelegate delegate;
+ ui::SetTextEditKeyBindingsDelegate(&delegate);
+#endif
+
+ SendKeyEvent(ui::VKEY_A, false, false);
+ EXPECT_STR_EQ("a", textfield_->text());
+ textfield_->clear();
+
+ // Undo/Redo command keys are handled by the textfield.
+ SendKeyEvent(ui::VKEY_Z, false, true);
EXPECT_TRUE(textfield_->key_received());
EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_TRUE(textfield_->text().empty());
textfield_->clear();
- // Now left key should not be handled.
- SendKeyEvent(ui::VKEY_LEFT);
+ SendKeyEvent(ui::VKEY_Z, true, true);
EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
+ EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_STR_EQ("a", textfield_->text());
textfield_->clear();
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ ui::SetTextEditKeyBindingsDelegate(NULL);
+#endif
}
-TEST_F(NativeTextfieldViewsTest, CursorMovement) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, CursorMovement) {
+ InitTextfield();
// Test with trailing whitespace.
textfield_->SetText(ASCIIToUTF16("one two hre "));
@@ -750,8 +653,8 @@ TEST_F(NativeTextfieldViewsTest, CursorMovement) {
EXPECT_STR_EQ("one two", last_contents_);
}
-TEST_F(NativeTextfieldViewsTest, FocusTraversalTest) {
- InitTextfields(Textfield::STYLE_DEFAULT, 3);
+TEST_F(TextfieldTest, FocusTraversalTest) {
+ InitTextfields(3);
textfield_->RequestFocus();
EXPECT_EQ(1, GetFocusedView()->id());
@@ -777,21 +680,21 @@ TEST_F(NativeTextfieldViewsTest, FocusTraversalTest) {
textfield_->RequestFocus();
EXPECT_EQ(1, GetFocusedView()->id());
- // Test if clicking on textfield view sets the focus to textfield_.
+ // Test if clicking on textfield view sets the focus.
widget_->GetFocusManager()->AdvanceFocus(true);
EXPECT_EQ(3, GetFocusedView()->id());
ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click);
EXPECT_EQ(1, GetFocusedView()->id());
}
-TEST_F(NativeTextfieldViewsTest, ContextMenuDisplayTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, ContextMenuDisplayTest) {
+ InitTextfield();
EXPECT_TRUE(textfield_->context_menu_controller());
textfield_->SetText(ASCIIToUTF16("hello world"));
ui::Clipboard::GetForCurrentThread()->Clear(ui::CLIPBOARD_TYPE_COPY_PASTE);
- textfield_view_->ClearEditHistory();
+ textfield_->ClearEditHistory();
EXPECT_TRUE(GetContextMenuModel());
VerifyTextfieldContextMenuContents(false, false, GetContextMenuModel());
@@ -805,183 +708,183 @@ TEST_F(NativeTextfieldViewsTest, ContextMenuDisplayTest) {
VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel());
// Exercise the "paste enabled?" check in the verifier.
- SetClipboardText("Test");
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel());
}
-TEST_F(NativeTextfieldViewsTest, DoubleAndTripleClickTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, DoubleAndTripleClickTest) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent double_click(
ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK);
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK,
+ ui::EF_LEFT_MOUSE_BUTTON);
// Test for double click.
- textfield_view_->OnMousePressed(click);
- textfield_view_->OnMouseReleased(release);
+ textfield_->OnMousePressed(click);
+ textfield_->OnMouseReleased(release);
EXPECT_TRUE(textfield_->GetSelectedText().empty());
- textfield_view_->OnMousePressed(double_click);
- textfield_view_->OnMouseReleased(release);
+ textfield_->OnMousePressed(double_click);
+ textfield_->OnMouseReleased(release);
EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
// Test for triple click.
- textfield_view_->OnMousePressed(click);
- textfield_view_->OnMouseReleased(release);
+ textfield_->OnMousePressed(click);
+ textfield_->OnMouseReleased(release);
EXPECT_STR_EQ("hello world", textfield_->GetSelectedText());
// Another click should reset back to double click.
- textfield_view_->OnMousePressed(click);
- textfield_view_->OnMouseReleased(release);
+ textfield_->OnMousePressed(click);
+ textfield_->OnMouseReleased(release);
EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
}
-TEST_F(NativeTextfieldViewsTest, DragToSelect) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, DragToSelect) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
const int kStart = GetCursorPositionX(5);
const int kEnd = 500;
gfx::Point start_point(kStart, 0);
gfx::Point end_point(kEnd, 0);
ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, start_point, start_point,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent click_b(ui::ET_MOUSE_PRESSED, end_point, end_point,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent drag_left(ui::ET_MOUSE_DRAGGED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
ui::MouseEvent drag_right(ui::ET_MOUSE_DRAGGED, end_point, end_point,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, end_point, end_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click_a);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click_a);
EXPECT_TRUE(textfield_->GetSelectedText().empty());
// Check that dragging left selects the beginning of the string.
- textfield_view_->OnMouseDragged(drag_left);
- string16 text_left = textfield_->GetSelectedText();
+ textfield_->OnMouseDragged(drag_left);
+ base::string16 text_left = textfield_->GetSelectedText();
EXPECT_STR_EQ("hello", text_left);
// Check that dragging right selects the rest of the string.
- textfield_view_->OnMouseDragged(drag_right);
- string16 text_right = textfield_->GetSelectedText();
+ textfield_->OnMouseDragged(drag_right);
+ base::string16 text_right = textfield_->GetSelectedText();
EXPECT_STR_EQ(" world", text_right);
// Check that releasing in the same location does not alter the selection.
- textfield_view_->OnMouseReleased(release);
+ textfield_->OnMouseReleased(release);
EXPECT_EQ(text_right, textfield_->GetSelectedText());
// Check that dragging from beyond the text length works too.
- textfield_view_->OnMousePressed(click_b);
- textfield_view_->OnMouseDragged(drag_left);
- textfield_view_->OnMouseReleased(release);
+ textfield_->OnMousePressed(click_b);
+ textfield_->OnMouseDragged(drag_left);
+ textfield_->OnMouseReleased(release);
EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText());
}
#if defined(OS_WIN)
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_AcceptDrop) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
ui::OSExchangeData data;
- string16 string(ASCIIToUTF16("string "));
+ base::string16 string(ASCIIToUTF16("string "));
data.SetString(string);
int formats = 0;
std::set<OSExchangeData::CustomFormat> custom_formats;
// Ensure that disabled textfields do not accept drops.
textfield_->SetEnabled(false);
- EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats));
EXPECT_EQ(0, formats);
EXPECT_TRUE(custom_formats.empty());
- EXPECT_FALSE(textfield_view_->CanDrop(data));
+ EXPECT_FALSE(textfield_->CanDrop(data));
textfield_->SetEnabled(true);
// Ensure that read-only textfields do not accept drops.
textfield_->SetReadOnly(true);
- EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats));
EXPECT_EQ(0, formats);
EXPECT_TRUE(custom_formats.empty());
- EXPECT_FALSE(textfield_view_->CanDrop(data));
+ EXPECT_FALSE(textfield_->CanDrop(data));
textfield_->SetReadOnly(false);
// Ensure that enabled and editable textfields do accept drops.
- EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
EXPECT_EQ(ui::OSExchangeData::STRING, formats);
EXPECT_TRUE(custom_formats.empty());
- EXPECT_TRUE(textfield_view_->CanDrop(data));
+ EXPECT_TRUE(textfield_->CanDrop(data));
gfx::Point drop_point(GetCursorPositionX(6), 0);
ui::DropTargetEvent drop(data, drop_point, drop_point,
ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE);
EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnDragUpdated(drop));
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_view_->OnPerformDrop(drop));
+ textfield_->OnDragUpdated(drop));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_->OnPerformDrop(drop));
EXPECT_STR_EQ("hello string world", textfield_->text());
// Ensure that textfields do not accept non-OSExchangeData::STRING types.
ui::OSExchangeData bad_data;
bad_data.SetFilename(base::FilePath(FILE_PATH_LITERAL("x")));
-#if defined(OS_WIN)
ui::OSExchangeData::CustomFormat fmt = ui::Clipboard::GetBitmapFormatType();
bad_data.SetPickledData(fmt, Pickle());
bad_data.SetFileContents(base::FilePath(L"x"), "x");
- bad_data.SetHtml(string16(ASCIIToUTF16("x")), GURL("x.org"));
+ bad_data.SetHtml(base::string16(ASCIIToUTF16("x")), GURL("x.org"));
ui::OSExchangeData::DownloadFileInfo download(base::FilePath(), NULL);
bad_data.SetDownloadFileInfo(download);
-#endif
- EXPECT_FALSE(textfield_view_->CanDrop(bad_data));
+ EXPECT_FALSE(textfield_->CanDrop(bad_data));
}
#endif
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_InitiateDrag) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, DragAndDrop_InitiateDrag) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello string world"));
// Ensure the textfield will provide selected text for drag data.
- string16 string;
+ base::string16 string;
ui::OSExchangeData data;
const gfx::Range kStringRange(6, 12);
textfield_->SelectRange(kStringRange);
const gfx::Point kStringPoint(GetCursorPositionX(9), 0);
- textfield_view_->WriteDragDataForView(NULL, kStringPoint, &data);
+ textfield_->WriteDragDataForView(NULL, kStringPoint, &data);
EXPECT_TRUE(data.GetString(&string));
EXPECT_EQ(textfield_->GetSelectedText(), string);
// Ensure that disabled textfields do not support drag operations.
textfield_->SetEnabled(false);
EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
- textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
+ textfield_->GetDragOperationsForView(NULL, kStringPoint));
textfield_->SetEnabled(true);
// Ensure that textfields without selections do not support drag operations.
textfield_->ClearSelection();
EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
- textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
+ textfield_->GetDragOperationsForView(NULL, kStringPoint));
textfield_->SelectRange(kStringRange);
// Ensure that password textfields do not support drag operations.
- textfield_->SetObscured(true);
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
- textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
- textfield_->SetObscured(false);
+ textfield_->GetDragOperationsForView(NULL, kStringPoint));
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
// Ensure that textfields only initiate drag operations inside the selection.
ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, kStringPoint, kStringPoint,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(press_event);
+ textfield_->OnMousePressed(press_event);
EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
- textfield_view_->GetDragOperationsForView(NULL, gfx::Point()));
- EXPECT_FALSE(textfield_view_->CanStartDragForView(NULL, gfx::Point(),
- gfx::Point()));
+ textfield_->GetDragOperationsForView(NULL, gfx::Point()));
+ EXPECT_FALSE(textfield_->CanStartDragForView(NULL, gfx::Point(),
+ gfx::Point()));
EXPECT_EQ(ui::DragDropTypes::DRAG_COPY,
- textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
- EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL, kStringPoint,
- gfx::Point()));
+ textfield_->GetDragOperationsForView(NULL, kStringPoint));
+ EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint,
+ gfx::Point()));
// Ensure that textfields support local moves.
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
- textfield_view_->GetDragOperationsForView(textfield_view_, kStringPoint));
+ textfield_->GetDragOperationsForView(textfield_, kStringPoint));
}
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, DragAndDrop_ToTheRight) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
- string16 string;
+ base::string16 string;
ui::OSExchangeData data;
int formats = 0;
int operations = 0;
@@ -991,31 +894,29 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) {
textfield_->SelectRange(gfx::Range(1, 5));
gfx::Point point(GetCursorPositionX(3), 0);
ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click_a);
- EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_,
- click_a.location(), gfx::Point()));
- operations = textfield_view_->GetDragOperationsForView(textfield_view_,
- click_a.location());
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click_a);
+ EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(),
+ gfx::Point()));
+ operations = textfield_->GetDragOperationsForView(textfield_,
+ click_a.location());
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
operations);
- textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data);
+ textfield_->WriteDragDataForView(NULL, click_a.location(), &data);
EXPECT_TRUE(data.GetString(&string));
EXPECT_EQ(textfield_->GetSelectedText(), string);
- EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
EXPECT_EQ(ui::OSExchangeData::STRING, formats);
EXPECT_TRUE(custom_formats.empty());
// Drop "ello" after "w".
const gfx::Point kDropPoint(GetCursorPositionX(7), 0);
- EXPECT_TRUE(textfield_view_->CanDrop(data));
+ EXPECT_TRUE(textfield_->CanDrop(data));
ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations);
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnDragUpdated(drop_a));
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnPerformDrop(drop_a));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
EXPECT_STR_EQ("h welloorld", textfield_->text());
- textfield_view_->OnDragDone();
+ textfield_->OnDragDone();
// Undo/Redo the drag&drop change.
SendKeyEvent(ui::VKEY_Z, false, true);
@@ -1032,11 +933,11 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) {
EXPECT_STR_EQ("h welloorld", textfield_->text());
}
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
- string16 string;
+ base::string16 string;
ui::OSExchangeData data;
int formats = 0;
int operations = 0;
@@ -1046,31 +947,29 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) {
textfield_->SelectRange(gfx::Range(5, 10));
gfx::Point point(GetCursorPositionX(7), 0);
ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click_a);
- EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_,
- click_a.location(), gfx::Point()));
- operations = textfield_view_->GetDragOperationsForView(textfield_view_,
- click_a.location());
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click_a);
+ EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(),
+ gfx::Point()));
+ operations = textfield_->GetDragOperationsForView(textfield_,
+ click_a.location());
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
operations);
- textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data);
+ textfield_->WriteDragDataForView(NULL, click_a.location(), &data);
EXPECT_TRUE(data.GetString(&string));
EXPECT_EQ(textfield_->GetSelectedText(), string);
- EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
EXPECT_EQ(ui::OSExchangeData::STRING, formats);
EXPECT_TRUE(custom_formats.empty());
// Drop " worl" after "h".
- EXPECT_TRUE(textfield_view_->CanDrop(data));
+ EXPECT_TRUE(textfield_->CanDrop(data));
gfx::Point drop_point(GetCursorPositionX(1), 0);
ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations);
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnDragUpdated(drop_a));
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnPerformDrop(drop_a));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
EXPECT_STR_EQ("h worlellod", textfield_->text());
- textfield_view_->OnDragDone();
+ textfield_->OnDragDone();
// Undo/Redo the drag&drop change.
SendKeyEvent(ui::VKEY_Z, false, true);
@@ -1087,42 +986,42 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) {
EXPECT_STR_EQ("h worlellod", textfield_->text());
}
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_Canceled) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, DragAndDrop_Canceled) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
// Start dragging "worl".
textfield_->SelectRange(gfx::Range(6, 10));
gfx::Point point(GetCursorPositionX(8), 0);
ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click);
ui::OSExchangeData data;
- textfield_view_->WriteDragDataForView(NULL, click.location(), &data);
- EXPECT_TRUE(textfield_view_->CanDrop(data));
+ textfield_->WriteDragDataForView(NULL, click.location(), &data);
+ EXPECT_TRUE(textfield_->CanDrop(data));
// Drag the text over somewhere valid, outside the current selection.
gfx::Point drop_point(GetCursorPositionX(2), 0);
ui::DropTargetEvent drop(data, drop_point, drop_point,
ui::DragDropTypes::DRAG_MOVE);
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_view_->OnDragUpdated(drop));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop));
// "Cancel" the drag, via move and release over the selection, and OnDragDone.
gfx::Point drag_point(GetCursorPositionX(9), 0);
ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, drag_point, drag_point,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, drag_point, drag_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMouseDragged(drag);
- textfield_view_->OnMouseReleased(release);
- textfield_view_->OnDragDone();
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseDragged(drag);
+ textfield_->OnMouseReleased(release);
+ textfield_->OnDragDone();
EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text());
}
-TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, ReadOnlyTest) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("read only"));
textfield_->SetReadOnly(true);
EXPECT_TRUE(textfield_->enabled());
- EXPECT_TRUE(textfield_->focusable());
+ EXPECT_TRUE(textfield_->IsFocusable());
SendKeyEvent(ui::VKEY_HOME);
EXPECT_EQ(0U, textfield_->GetCursorPosition());
@@ -1140,32 +1039,32 @@ TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) {
EXPECT_STR_EQ("read only", textfield_->GetSelectedText());
// Cut should be disabled.
- SetClipboardText("Test");
- EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_view_->ExecuteCommand(IDS_APP_CUT, 0);
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
+ textfield_->ExecuteCommand(IDS_APP_CUT, 0);
SendKeyEvent(ui::VKEY_X, false, true);
SendKeyEvent(ui::VKEY_DELETE, true, false);
- EXPECT_STR_EQ("Test", string16(GetClipboardText()));
+ EXPECT_STR_EQ("Test", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("read only", textfield_->text());
// Paste should be disabled.
- EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0);
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
+ textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
SendKeyEvent(ui::VKEY_V, false, true);
SendKeyEvent(ui::VKEY_INSERT, true, false);
EXPECT_STR_EQ("read only", textfield_->text());
// Copy should work normally.
- SetClipboardText("Test");
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_view_->ExecuteCommand(IDS_APP_COPY, 0);
- EXPECT_STR_EQ("read only", string16(GetClipboardText()));
- SetClipboardText("Test");
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
+ textfield_->ExecuteCommand(IDS_APP_COPY, 0);
+ EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
SendKeyEvent(ui::VKEY_C, false, true);
- EXPECT_STR_EQ("read only", string16(GetClipboardText()));
- SetClipboardText("Test");
+ EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
SendKeyEvent(ui::VKEY_INSERT, false, true);
- EXPECT_STR_EQ("read only", string16(GetClipboardText()));
+ EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
// SetText should work even in read only mode.
textfield_->SetText(ASCIIToUTF16(" four five six "));
@@ -1183,8 +1082,8 @@ TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) {
EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
}
-TEST_F(NativeTextfieldViewsTest, TextInputClientTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, TextInputClientTest) {
+ InitTextfield();
ui::TextInputClient* client = textfield_->GetTextInputClient();
EXPECT_TRUE(client);
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, client->GetTextInputType());
@@ -1199,15 +1098,9 @@ TEST_F(NativeTextfieldViewsTest, TextInputClientTest) {
EXPECT_TRUE(client->GetSelectionRange(&range));
EXPECT_EQ(gfx::Range(1, 4), range);
- // This code can't be compiled because of a bug in base::Callback.
-#if 0
- GetTextHelper helper;
- base::Callback<void(string16)> callback =
- base::Bind(&GetTextHelper::set_text, base::Unretained(&helper));
-
- EXPECT_TRUE(client->GetTextFromRange(range, callback));
- EXPECT_STR_EQ("123", helper.text());
-#endif
+ base::string16 substring;
+ EXPECT_TRUE(client->GetTextFromRange(range, &substring));
+ EXPECT_STR_EQ("123", substring);
EXPECT_TRUE(client->DeleteRange(range));
EXPECT_STR_EQ("0456789", textfield_->text());
@@ -1227,8 +1120,8 @@ TEST_F(NativeTextfieldViewsTest, TextInputClientTest) {
EXPECT_TRUE(client->GetCompositionTextRange(&range));
EXPECT_STR_EQ("0321456789", textfield_->text());
EXPECT_EQ(gfx::Range(1, 4), range);
- EXPECT_EQ(2, on_before_user_action_);
- EXPECT_EQ(2, on_after_user_action_);
+ EXPECT_EQ(1, on_before_user_action_);
+ EXPECT_EQ(1, on_after_user_action_);
input_method_->SetResultTextForNextKey(UTF8ToUTF16("123"));
on_before_user_action_ = on_after_user_action_ = 0;
@@ -1239,8 +1132,8 @@ TEST_F(NativeTextfieldViewsTest, TextInputClientTest) {
EXPECT_FALSE(client->HasCompositionText());
EXPECT_FALSE(input_method_->cancel_composition_called());
EXPECT_STR_EQ("0123456789", textfield_->text());
- EXPECT_EQ(2, on_before_user_action_);
- EXPECT_EQ(2, on_after_user_action_);
+ EXPECT_EQ(1, on_before_user_action_);
+ EXPECT_EQ(1, on_after_user_action_);
input_method_->Clear();
input_method_->SetCompositionTextForNextKey(composition);
@@ -1283,13 +1176,13 @@ TEST_F(NativeTextfieldViewsTest, TextInputClientTest) {
textfield_->SetReadOnly(false);
input_method_->Clear();
- textfield_->SetObscured(true);
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
EXPECT_TRUE(input_method_->text_input_type_changed());
EXPECT_TRUE(textfield_->GetTextInputClient());
}
-TEST_F(NativeTextfieldViewsTest, UndoRedoTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, UndoRedoTest) {
+ InitTextfield();
SendKeyEvent(ui::VKEY_A);
EXPECT_STR_EQ("a", textfield_->text());
SendKeyEvent(ui::VKEY_Z, false, true);
@@ -1313,8 +1206,7 @@ TEST_F(NativeTextfieldViewsTest, UndoRedoTest) {
// SetText
SendKeyEvent(ui::VKEY_C);
// Undo'ing append moves the cursor to the end for now.
- // no-op SetText won't add new edit. See TextfieldViewsModel::SetText
- // description.
+ // A no-op SetText won't add a new edit; see TextfieldModel::SetText.
EXPECT_STR_EQ("abc", textfield_->text());
textfield_->SetText(ASCIIToUTF16("abc"));
EXPECT_STR_EQ("abc", textfield_->text());
@@ -1383,62 +1275,70 @@ TEST_F(NativeTextfieldViewsTest, UndoRedoTest) {
EXPECT_STR_EQ("", textfield_->text());
}
-TEST_F(NativeTextfieldViewsTest, CutCopyPaste) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, CutCopyPaste) {
+ InitTextfield();
// Ensure IDS_APP_CUT cuts.
textfield_->SetText(ASCIIToUTF16("123"));
textfield_->SelectAll(false);
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_view_->ExecuteCommand(IDS_APP_CUT, 0);
- EXPECT_STR_EQ("123", string16(GetClipboardText()));
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
+ textfield_->ExecuteCommand(IDS_APP_CUT, 0);
+ EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
// Ensure [Ctrl]+[x] cuts and [Ctrl]+[Alt][x] does nothing.
textfield_->SetText(ASCIIToUTF16("456"));
textfield_->SelectAll(false);
SendKeyEvent(ui::VKEY_X, true, false, true, false);
- EXPECT_STR_EQ("123", string16(GetClipboardText()));
+ EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("456", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
SendKeyEvent(ui::VKEY_X, false, true);
- EXPECT_STR_EQ("456", string16(GetClipboardText()));
+ EXPECT_STR_EQ("456", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
// Ensure [Shift]+[Delete] cuts.
textfield_->SetText(ASCIIToUTF16("123"));
textfield_->SelectAll(false);
SendKeyEvent(ui::VKEY_DELETE, true, false);
- EXPECT_STR_EQ("123", string16(GetClipboardText()));
+ EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
// Ensure IDS_APP_COPY copies.
textfield_->SetText(ASCIIToUTF16("789"));
textfield_->SelectAll(false);
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_view_->ExecuteCommand(IDS_APP_COPY, 0);
- EXPECT_STR_EQ("789", string16(GetClipboardText()));
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
+ textfield_->ExecuteCommand(IDS_APP_COPY, 0);
+ EXPECT_STR_EQ("789", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
// Ensure [Ctrl]+[c] copies and [Ctrl]+[Alt][c] does nothing.
textfield_->SetText(ASCIIToUTF16("012"));
textfield_->SelectAll(false);
SendKeyEvent(ui::VKEY_C, true, false, true, false);
- EXPECT_STR_EQ("789", string16(GetClipboardText()));
+ EXPECT_STR_EQ("789", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
SendKeyEvent(ui::VKEY_C, false, true);
- EXPECT_STR_EQ("012", string16(GetClipboardText()));
+ EXPECT_STR_EQ("012", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
// Ensure [Ctrl]+[Insert] copies.
textfield_->SetText(ASCIIToUTF16("345"));
textfield_->SelectAll(false);
SendKeyEvent(ui::VKEY_INSERT, false, true);
- EXPECT_STR_EQ("345", string16(GetClipboardText()));
+ EXPECT_STR_EQ("345", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("345", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
// Ensure IDS_APP_PASTE, [Ctrl]+[V], and [Shift]+[Insert] pastes;
// also ensure that [Ctrl]+[Alt]+[V] does nothing.
- SetClipboardText("abc");
- textfield_->SetText(string16());
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0);
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "abc");
+ textfield_->SetText(base::string16());
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
+ textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
EXPECT_STR_EQ("abc", textfield_->text());
SendKeyEvent(ui::VKEY_V, false, true);
EXPECT_STR_EQ("abcabc", textfield_->text());
@@ -1450,12 +1350,13 @@ TEST_F(NativeTextfieldViewsTest, CutCopyPaste) {
// Ensure [Ctrl]+[Shift]+[Insert] is a no-op.
textfield_->SelectAll(false);
SendKeyEvent(ui::VKEY_INSERT, true, true);
- EXPECT_STR_EQ("abc", string16(GetClipboardText()));
+ EXPECT_STR_EQ("abc", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_STR_EQ("abcabcabc", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
}
-TEST_F(NativeTextfieldViewsTest, OvertypeMode) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, OvertypeMode) {
+ InitTextfield();
// Overtype mode should be disabled (no-op [Insert]).
textfield_->SetText(ASCIIToUTF16("2"));
SendKeyEvent(ui::VKEY_HOME);
@@ -1464,8 +1365,8 @@ TEST_F(NativeTextfieldViewsTest, OvertypeMode) {
EXPECT_STR_EQ("12", textfield_->text());
}
-TEST_F(NativeTextfieldViewsTest, TextCursorDisplayTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, TextCursorDisplayTest) {
+ InitTextfield();
// LTR-RTL string in LTR context.
SendKeyEvent('a');
EXPECT_STR_EQ("a", textfield_->text());
@@ -1516,11 +1417,11 @@ TEST_F(NativeTextfieldViewsTest, TextCursorDisplayTest) {
EXPECT_LT(prev_x, x);
}
-TEST_F(NativeTextfieldViewsTest, TextCursorDisplayInRTLTest) {
+TEST_F(TextfieldTest, TextCursorDisplayInRTLTest) {
std::string locale = l10n_util::GetApplicationLocale("");
base::i18n::SetICUDefaultLocale("he");
- InitTextfield(Textfield::STYLE_DEFAULT);
+ InitTextfield();
// LTR-RTL string in RTL context.
SendKeyEvent('a');
EXPECT_STR_EQ("a", textfield_->text());
@@ -1574,8 +1475,8 @@ TEST_F(NativeTextfieldViewsTest, TextCursorDisplayInRTLTest) {
base::i18n::SetICUDefaultLocale(locale);
}
-TEST_F(NativeTextfieldViewsTest, HitInsideTextAreaTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, HitInsideTextAreaTest) {
+ InitTextfield();
textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
std::vector<gfx::Rect> cursor_bounds;
@@ -1629,8 +1530,8 @@ TEST_F(NativeTextfieldViewsTest, HitInsideTextAreaTest) {
}
}
-TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, HitOutsideTextAreaTest) {
+ InitTextfield();
// LTR-RTL string in LTR context.
textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
@@ -1661,11 +1562,11 @@ TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaTest) {
EXPECT_EQ(bound, GetCursorBounds());
}
-TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaInRTLTest) {
+TEST_F(TextfieldTest, HitOutsideTextAreaInRTLTest) {
std::string locale = l10n_util::GetApplicationLocale("");
base::i18n::SetICUDefaultLocale("he");
- InitTextfield(Textfield::STYLE_DEFAULT);
+ InitTextfield();
// RTL-LTR string in RTL context.
textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab"));
@@ -1697,10 +1598,10 @@ TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaInRTLTest) {
base::i18n::SetICUDefaultLocale(locale);
}
-TEST_F(NativeTextfieldViewsTest, OverflowTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, OverflowTest) {
+ InitTextfield();
- string16 str;
+ base::string16 str;
for (int i = 0; i < 500; ++i)
SendKeyEvent('a');
SendKeyEvent(kHebrewLetterSamekh);
@@ -1723,13 +1624,13 @@ TEST_F(NativeTextfieldViewsTest, OverflowTest) {
EXPECT_EQ(501U, textfield_->GetCursorPosition());
}
-TEST_F(NativeTextfieldViewsTest, OverflowInRTLTest) {
+TEST_F(TextfieldTest, OverflowInRTLTest) {
std::string locale = l10n_util::GetApplicationLocale("");
base::i18n::SetICUDefaultLocale("he");
- InitTextfield(Textfield::STYLE_DEFAULT);
+ InitTextfield();
- string16 str;
+ base::string16 str;
for (int i = 0; i < 500; ++i)
SendKeyEvent('a');
SendKeyEvent(kHebrewLetterSamekh);
@@ -1754,10 +1655,10 @@ TEST_F(NativeTextfieldViewsTest, OverflowInRTLTest) {
base::i18n::SetICUDefaultLocale(locale);
}
-TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBoundsTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, GetCompositionCharacterBoundsTest) {
+ InitTextfield();
- string16 str;
+ base::string16 str;
const uint32 char_count = 10UL;
ui::CompositionText composition;
composition.text = UTF8ToUTF16("0123456789");
@@ -1777,8 +1678,8 @@ TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBoundsTest) {
gfx::Rect cursor_bounds = GetCursorBounds();
gfx::Point top_left(prev_cursor.x(), prev_cursor.y());
gfx::Point bottom_right(cursor_bounds.x(), prev_cursor.bottom());
- views::View::ConvertPointToScreen(textfield_view_, &top_left);
- views::View::ConvertPointToScreen(textfield_view_, &bottom_right);
+ views::View::ConvertPointToScreen(textfield_, &top_left);
+ views::View::ConvertPointToScreen(textfield_, &bottom_right);
char_rect_in_screen_coord[i].set_origin(top_left);
char_rect_in_screen_coord[i].set_width(bottom_right.x() - top_left.x());
char_rect_in_screen_coord[i].set_height(bottom_right.y() - top_left.y());
@@ -1798,10 +1699,10 @@ TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBoundsTest) {
EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 100, &rect));
}
-TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBounds_ComplexText) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, GetCompositionCharacterBounds_ComplexText) {
+ InitTextfield();
- const char16 kUtf16Chars[] = {
+ const base::char16 kUtf16Chars[] = {
// U+0020 SPACE
0x0020,
// U+1F408 (CAT) as surrogate pair
@@ -1835,8 +1736,8 @@ TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBounds_ComplexText) {
// The word we select by double clicking should remain selected regardless of
// where we drag the mouse afterwards without releasing the left button.
-TEST_F(NativeTextfieldViewsTest, KeepInitiallySelectedWord) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, KeepInitiallySelectedWord) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("abc def ghi"));
@@ -1850,73 +1751,192 @@ TEST_F(NativeTextfieldViewsTest, KeepInitiallySelectedWord) {
const gfx::Point middle(middle_cursor.x(),
middle_cursor.y() + middle_cursor.height() / 2);
ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, middle, middle,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(press_event);
+ textfield_->OnMousePressed(press_event);
EXPECT_EQ(gfx::Range(4, 7), textfield_->GetSelectedRange());
// Drag the mouse to the beginning of the textfield.
ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, beginning, beginning,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMouseDragged(drag_event);
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
+ textfield_->OnMouseDragged(drag_event);
EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange());
}
-// Touch selection and draggin currently only works for chromeos.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+TEST_F(TextfieldTest, SelectionClipboard) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("0123"));
+ gfx::Point point_1(GetCursorPositionX(1), 0);
+ gfx::Point point_2(GetCursorPositionX(2), 0);
+ gfx::Point point_3(GetCursorPositionX(3), 0);
+ gfx::Point point_4(GetCursorPositionX(4), 0);
+
+ // Text selected by the mouse should be placed on the selection clipboard.
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, point_1, point_1,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(press);
+ ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, point_3, point_3,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseDragged(drag);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point_3, point_3,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release);
+ EXPECT_EQ(gfx::Range(1, 3), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("12", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+
+ // Select-all should update the selection clipboard.
+ SendKeyEvent(ui::VKEY_A, false, true);
+ EXPECT_EQ(gfx::Range(0, 4), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Shift-click selection modifications should update the clipboard.
+ NonClientMouseClick();
+ ui::MouseEvent press_2(ui::ET_MOUSE_PRESSED, point_2, point_2,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ press_2.set_flags(press_2.flags() | ui::EF_SHIFT_DOWN);
+ textfield_->OnMousePressed(press_2);
+ ui::MouseEvent release_2(ui::ET_MOUSE_RELEASED, point_2, point_2,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release_2);
+ EXPECT_EQ(gfx::Range(0, 2), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("01", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Shift-Left/Right should update the selection clipboard.
+ SendKeyEvent(ui::VKEY_RIGHT, true, false);
+ EXPECT_STR_EQ("012", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+ SendKeyEvent(ui::VKEY_LEFT, true, false);
+ EXPECT_STR_EQ("01", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+ SendKeyEvent(ui::VKEY_RIGHT, true, true);
+ EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Moving the cursor without a selection should not change the clipboard.
+ SendKeyEvent(ui::VKEY_LEFT, false, false);
+ EXPECT_EQ(gfx::Range(0, 0), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+
+ // Middle clicking should paste at the mouse (not cursor) location.
+ ui::MouseEvent middle(ui::ET_MOUSE_PRESSED, point_4, point_4,
+ ui::EF_MIDDLE_MOUSE_BUTTON, ui::EF_MIDDLE_MOUSE_BUTTON);
+ textfield_->OnMousePressed(middle);
+ EXPECT_STR_EQ("01230123", textfield_->text());
+ EXPECT_EQ(gfx::Range(0, 0), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+
+ // Middle click pasting should adjust trailing cursors.
+ textfield_->SelectRange(gfx::Range(5, 5));
+ textfield_->OnMousePressed(middle);
+ EXPECT_STR_EQ("012301230123", textfield_->text());
+ EXPECT_EQ(gfx::Range(9, 9), textfield_->GetSelectedRange());
+
+ // Middle click pasting should adjust trailing selections.
+ textfield_->SelectRange(gfx::Range(7, 9));
+ textfield_->OnMousePressed(middle);
+ EXPECT_STR_EQ("0123012301230123", textfield_->text());
+ EXPECT_EQ(gfx::Range(11, 13), textfield_->GetSelectedRange());
+
+ // Middle clicking in the selection should clear the clipboard and selection.
+ textfield_->SelectRange(gfx::Range(2, 6));
+ textfield_->OnMousePressed(middle);
+ EXPECT_STR_EQ("0123012301230123", textfield_->text());
+ EXPECT_EQ(gfx::Range(6, 6), textfield_->GetSelectedRange());
+ EXPECT_TRUE(GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION).empty());
+
+ // Double and triple clicking should update the clipboard contents.
+ textfield_->SetText(ASCIIToUTF16("ab cd ef"));
+ gfx::Point word(GetCursorPositionX(4), 0);
+ ui::MouseEvent press_word(ui::ET_MOUSE_PRESSED, word, word,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(press_word);
+ ui::MouseEvent release_word(ui::ET_MOUSE_RELEASED, word, word,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release_word);
+ ui::MouseEvent double_click(ui::ET_MOUSE_PRESSED, word, word,
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(double_click);
+ textfield_->OnMouseReleased(release_word);
+ EXPECT_EQ(gfx::Range(3, 5), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("cd", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+ textfield_->OnMousePressed(press_word);
+ textfield_->OnMouseReleased(release_word);
+ EXPECT_EQ(gfx::Range(0, 8), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("ab cd ef", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Selecting a range of text without any user interaction should not change
+ // the clipboard content.
+ textfield_->SelectRange(gfx::Range(0, 3));
+ EXPECT_STR_EQ("ab ", textfield_->GetSelectedText());
+ EXPECT_STR_EQ("ab cd ef", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+
+ SetClipboardText(ui::CLIPBOARD_TYPE_SELECTION, "other");
+ textfield_->SelectAll(false);
+ EXPECT_STR_EQ("other", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+}
+#endif
+
+// Touch selection and dragging currently only works for chromeos.
#if defined(OS_CHROMEOS)
-TEST_F(NativeTextfieldViewsTest, TouchSelectionAndDraggingTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, TouchSelectionAndDraggingTest) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
- EXPECT_FALSE(GetTouchSelectionController());
- const int eventX = GetCursorPositionX(2);
- const int eventY = 0;
+ EXPECT_FALSE(test_api_->touch_selection_controller());
+ const int x = GetCursorPositionX(2);
+ GestureEventForTest tap(ui::ET_GESTURE_TAP, x, 0, 1.0f, 0.0f);
+ GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, x, 0, 0.0f, 0.0f);
+ GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, x, 0, 0.0f, 0.0f);
CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
// Tapping on the textfield should turn on the TouchSelectionController.
- GestureEventForTest tap(ui::ET_GESTURE_TAP, eventX, eventY, 1.0f, 0.0f);
- textfield_view_->OnGestureEvent(&tap);
- EXPECT_TRUE(GetTouchSelectionController());
+ textfield_->OnGestureEvent(&tap);
+ EXPECT_TRUE(test_api_->touch_selection_controller());
// Un-focusing the textfield should reset the TouchSelectionController
- textfield_view_->GetFocusManager()->ClearFocus();
- EXPECT_FALSE(GetTouchSelectionController());
+ textfield_->GetFocusManager()->ClearFocus();
+ EXPECT_FALSE(test_api_->touch_selection_controller());
// With touch editing enabled, long press should not show context menu.
// Instead, select word and invoke TouchSelectionController.
- GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, eventX, eventY, 0.0f,
- 0.0f);
- textfield_view_->OnGestureEvent(&tap_down);
- GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, eventX, eventY,
- 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&long_press);
+ textfield_->OnGestureEvent(&tap_down);
+ textfield_->OnGestureEvent(&long_press);
EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
- EXPECT_TRUE(GetTouchSelectionController());
+ EXPECT_TRUE(test_api_->touch_selection_controller());
- // Long pressing again in the selecting region should not do anything since
- // touch drag drop is not yet enabled.
- textfield_view_->OnGestureEvent(&tap_down);
- textfield_view_->OnGestureEvent(&long_press);
+ // With touch drag drop enabled, long pressing in the selected region should
+ // start a drag and remove TouchSelectionController.
+ ASSERT_TRUE(switches::IsTouchDragDropEnabled());
+ textfield_->OnGestureEvent(&tap_down);
+ textfield_->OnGestureEvent(&long_press);
EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
- EXPECT_TRUE(GetTouchSelectionController());
- EXPECT_TRUE(long_press.handled());
+ EXPECT_FALSE(test_api_->touch_selection_controller());
- // After enabling touch drag drop, long pressing in the selected region should
- // start a drag and remove TouchSelectionController.
+ // After disabling touch drag drop, long pressing again in the selection
+ // region should not do anything.
CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableTouchDragDrop);
- textfield_view_->OnGestureEvent(&tap_down);
-
- // Create a new long press event since the previous one is not marked handled.
- GestureEventForTest long_press2(ui::ET_GESTURE_LONG_PRESS, eventX, eventY,
- 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&long_press2);
+ switches::kDisableTouchDragDrop);
+ ASSERT_FALSE(switches::IsTouchDragDropEnabled());
+ textfield_->OnGestureEvent(&tap_down);
+ textfield_->OnGestureEvent(&long_press);
EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
- EXPECT_FALSE(GetTouchSelectionController());
+ EXPECT_TRUE(test_api_->touch_selection_controller());
+ EXPECT_TRUE(long_press.handled());
}
-TEST_F(NativeTextfieldViewsTest, TouchScrubbingSelection) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, TouchScrubbingSelection) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
- EXPECT_FALSE(GetTouchSelectionController());
+ EXPECT_FALSE(test_api_->touch_selection_controller());
CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
@@ -1926,37 +1946,37 @@ TEST_F(NativeTextfieldViewsTest, TouchScrubbingSelection) {
GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, scrubbing_start, 0,
0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&tap_down);
+ textfield_->OnGestureEvent(&tap_down);
GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, scrubbing_start, 0,
0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&tap_cancel);
+ textfield_->OnGestureEvent(&tap_cancel);
GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, scrubbing_start,
0, 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&scroll_begin);
+ textfield_->OnGestureEvent(&scroll_begin);
GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, scrubbing_end,
0, scrubbing_end - scrubbing_start, 0.0f);
- textfield_view_->OnGestureEvent(&scroll_update);
+ textfield_->OnGestureEvent(&scroll_update);
GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, scrubbing_end, 0,
0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&scroll_end);
+ textfield_->OnGestureEvent(&scroll_end);
GestureEventForTest end(ui::ET_GESTURE_END, scrubbing_end, 0, 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&end);
+ textfield_->OnGestureEvent(&end);
// In the end, part of text should have been selected and handles should have
// appeared.
EXPECT_STR_EQ("ello ", textfield_->GetSelectedText());
- EXPECT_TRUE(GetTouchSelectionController());
+ EXPECT_TRUE(test_api_->touch_selection_controller());
}
#endif
-// Long_Press gesture in NativeTextfieldViews can initiate a drag and drop now.
-TEST_F(NativeTextfieldViewsTest, TestLongPressInitiatesDragDrop) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+// Long_Press gesture in Textfield can initiate a drag and drop now.
+TEST_F(TextfieldTest, TestLongPressInitiatesDragDrop) {
+ InitTextfield();
textfield_->SetText(ASCIIToUTF16("Hello string world"));
// Ensure the textfield will provide selected text for drag data.
@@ -1970,13 +1990,13 @@ TEST_F(NativeTextfieldViewsTest, TestLongPressInitiatesDragDrop) {
// Create a long press event in the selected region should start a drag.
GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, kStringPoint.x(),
kStringPoint.y(), 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&long_press);
- EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL,
- kStringPoint, kStringPoint));
+ textfield_->OnGestureEvent(&long_press);
+ EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint,
+ kStringPoint));
}
-TEST_F(NativeTextfieldViewsTest, GetTextfieldBaseline_FontFallbackTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
+TEST_F(TextfieldTest, GetTextfieldBaseline_FontFallbackTest) {
+ InitTextfield();
textfield_->SetText(UTF8ToUTF16("abc"));
const int old_baseline = textfield_->GetBaseline();
diff --git a/chromium/ui/views/controls/throbber.cc b/chromium/ui/views/controls/throbber.cc
index 25272de0536..5df35606378 100644
--- a/chromium/ui/views/controls/throbber.cc
+++ b/chromium/ui/views/controls/throbber.cc
@@ -68,7 +68,7 @@ void Throbber::Run() {
SchedulePaint();
}
-gfx::Size Throbber::GetPreferredSize() {
+gfx::Size Throbber::GetPreferredSize() const {
return gfx::Size(frames_->height(), frames_->height());
}
diff --git a/chromium/ui/views/controls/throbber.h b/chromium/ui/views/controls/throbber.h
index 8ae3895a22a..08188c39cf5 100644
--- a/chromium/ui/views/controls/throbber.h
+++ b/chromium/ui/views/controls/throbber.h
@@ -37,7 +37,7 @@ class VIEWS_EXPORT Throbber : public View {
void SetFrames(const gfx::ImageSkia* frames);
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
protected:
diff --git a/chromium/ui/views/controls/tree/tree_view.cc b/chromium/ui/views/controls/tree/tree_view.cc
index 2c7bd55c396..f514fe45fcd 100644
--- a/chromium/ui/views/controls/tree/tree_view.cc
+++ b/chromium/ui/views/controls/tree/tree_view.cc
@@ -9,11 +9,12 @@
#include "base/i18n/rtl.h"
#include "base/message_loop/message_loop.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/skia_util.h"
@@ -78,8 +79,7 @@ TreeView::TreeView()
editable_(true),
controller_(NULL),
root_shown_(true),
- has_custom_icons_(false),
- row_height_(font_.GetHeight() + kTextVerticalPadding * 2) {
+ row_height_(font_list_.GetHeight() + kTextVerticalPadding * 2) {
SetFocusable(true);
closed_icon_ = *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
(base::i18n::IsRTL() ? IDR_FOLDER_CLOSED_RTL
@@ -158,9 +158,9 @@ void TreeView::StartEditing(TreeModelNode* node) {
// Add the editor immediately as GetPreferredSize returns the wrong thing if
// not parented.
AddChildView(editor_);
- editor_->SetFont(font_);
+ editor_->SetFontList(font_list_);
empty_editor_size_ = editor_->GetPreferredSize();
- editor_->SetController(this);
+ editor_->set_controller(this);
}
editor_->SetText(selected_node_->model_node()->GetTitle());
LayoutEditor();
@@ -245,7 +245,7 @@ void TreeView::SetSelectedNode(TreeModelNode* model_node) {
if (changed) {
// TODO(dmazzoni): Decide if EVENT_SELECTION_CHANGED is a better choice for
// sub-item selection event.
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
}
@@ -350,7 +350,7 @@ void TreeView::Layout() {
LayoutEditor();
}
-gfx::Size TreeView::GetPreferredSize() {
+gfx::Size TreeView::GetPreferredSize() const {
return preferred_size_;
}
@@ -403,14 +403,14 @@ void TreeView::ShowContextMenu(const gfx::Point& p,
View::ShowContextMenu(p, source_type);
}
-void TreeView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_OUTLINE;
- state->state = ui::AccessibilityTypes::STATE_READONLY;
+void TreeView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_TREE;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
if (!selected_node_)
return;
// Get selected item info.
- state->role = ui::AccessibilityTypes::ROLE_OUTLINEITEM;
+ state->role = ui::AX_ROLE_TREE_ITEM;
state->name = selected_node_->model_node()->GetTitle();
}
@@ -482,7 +482,7 @@ void TreeView::TreeNodeChanged(TreeModel* model, TreeModelNode* model_node) {
}
void TreeView::ContentsChanged(Textfield* sender,
- const string16& new_contents) {
+ const base::string16& new_contents) {
}
bool TreeView::HandleKeyEvent(Textfield* sender,
@@ -525,7 +525,7 @@ void TreeView::SetSelectedRow(int row) {
SetSelectedNode(GetNodeForRow(row));
}
-string16 TreeView::GetTextForRow(int row) {
+base::string16 TreeView::GetTextForRow(int row) {
return GetNodeForRow(row)->GetTitle();
}
@@ -694,7 +694,7 @@ void TreeView::ConfigureInternalNode(TreeModelNode* model_node,
void TreeView::UpdateNodeTextWidth(InternalNode* node) {
int width = 0, height = 0;
- gfx::Canvas::SizeStringInt(node->model_node()->GetTitle(), font_,
+ gfx::Canvas::SizeStringInt(node->model_node()->GetTitle(), font_list_,
&width, &height, 0, gfx::Canvas::NO_ELLIPSIS);
node->set_text_width(width);
}
@@ -729,7 +729,7 @@ void TreeView::LayoutEditor() {
row_bounds.set_width(row_bounds.width() - text_offset_);
row_bounds.Inset(kTextHorizontalPadding, kTextVerticalPadding);
row_bounds.Inset(-empty_editor_size_.width() / 2,
- -(empty_editor_size_.height() - font_.GetHeight()) / 2);
+ -(empty_editor_size_.height() - font_list_.GetHeight()) / 2);
// Give a little extra space for editing.
row_bounds.set_width(row_bounds.width() + 50);
editor_->SetBoundsRect(row_bounds);
@@ -803,12 +803,14 @@ void TreeView::PaintRow(gfx::Canvas* canvas,
}
const ui::NativeTheme::ColorId color_id =
text_color_id(HasFocus(), node == selected_node_);
- canvas->DrawStringInt(node->model_node()->GetTitle(), font_,
- GetNativeTheme()->GetSystemColor(color_id),
- text_bounds.x() + kTextHorizontalPadding,
- text_bounds.y() + kTextVerticalPadding,
- text_bounds.width() - kTextHorizontalPadding * 2,
- text_bounds.height() - kTextVerticalPadding * 2);
+ const gfx::Rect internal_bounds(
+ text_bounds.x() + kTextHorizontalPadding,
+ text_bounds.y() + kTextVerticalPadding,
+ text_bounds.width() - kTextHorizontalPadding * 2,
+ text_bounds.height() - kTextVerticalPadding * 2);
+ canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_,
+ GetNativeTheme()->GetSystemColor(color_id),
+ internal_bounds);
}
}
diff --git a/chromium/ui/views/controls/tree/tree_view.h b/chromium/ui/views/controls/tree/tree_view.h
index de571c789bf..3cae3b52376 100644
--- a/chromium/ui/views/controls/tree/tree_view.h
+++ b/chromium/ui/views/controls/tree/tree_view.h
@@ -11,13 +11,17 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/models/tree_node_model.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/controls/prefix_delegate.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/view.h"
+namespace gfx {
+class Rect;
+} // namespace gfx
+
namespace views {
class Textfield;
@@ -117,14 +121,14 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
// View overrides:
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual void ShowContextMenu(const gfx::Point& p,
ui::MenuSourceType source_type) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
// TreeModelObserver overrides:
@@ -141,7 +145,7 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
// TextfieldController overrides:
virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) OVERRIDE;
+ const base::string16& new_contents) OVERRIDE;
virtual bool HandleKeyEvent(Textfield* sender,
const ui::KeyEvent& key_event) OVERRIDE;
@@ -155,7 +159,7 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
virtual int GetRowCount() OVERRIDE;
virtual int GetSelectedRow() OVERRIDE;
virtual void SetSelectedRow(int row) OVERRIDE;
- virtual string16 GetTextForRow(int row) OVERRIDE;
+ virtual base::string16 GetTextForRow(int row) OVERRIDE;
protected:
// View overrides:
@@ -370,14 +374,11 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
// Whether or not the root is shown in the tree.
bool root_shown_;
- // Did the model return a non-empty set of icons from GetIcons?
- bool has_custom_icons_;
-
// Cached preferred size.
gfx::Size preferred_size_;
- // Font used to display text.
- gfx::Font font_;
+ // Font list used to display text.
+ gfx::FontList font_list_;
// Height of each row. Based on font and some padding.
int row_height_;
diff --git a/chromium/ui/views/controls/tree/tree_view_unittest.cc b/chromium/ui/views/controls/tree/tree_view_unittest.cc
index 1864ff9a9bf..bf73da99ec1 100644
--- a/chromium/ui/views/controls/tree/tree_view_unittest.cc
+++ b/chromium/ui/views/controls/tree/tree_view_unittest.cc
@@ -17,6 +17,8 @@ using ui::TreeModel;
using ui::TreeModelNode;
using ui::TreeNode;
+using base::ASCIIToUTF16;
+
namespace views {
class TestNode : public TreeNode<TestNode> {
@@ -68,7 +70,7 @@ class TreeViewTest : public ViewsTestBase {
private:
std::string InternalNodeAsString(TreeView::InternalNode* node);
- TestNode* GetNodeByTitleImpl(TestNode* node, const string16& title);
+ TestNode* GetNodeByTitleImpl(TestNode* node, const base::string16& title);
DISALLOW_COPY_AND_ASSIGN(TreeViewTest);
};
@@ -88,12 +90,14 @@ std::string TreeViewTest::TreeViewContentsAsString() {
std::string TreeViewTest::GetSelectedNodeTitle() {
TreeModelNode* model_node = tree_.GetSelectedNode();
- return model_node ? UTF16ToASCII(model_node->GetTitle()) : std::string();
+ return model_node ? base::UTF16ToASCII(model_node->GetTitle())
+ : std::string();
}
std::string TreeViewTest::GetEditingNodeTitle() {
TreeModelNode* model_node = tree_.GetEditingNode();
- return model_node ? UTF16ToASCII(model_node->GetTitle()) : std::string();
+ return model_node ? base::UTF16ToASCII(model_node->GetTitle())
+ : std::string();
}
TestNode* TreeViewTest::GetNodeByTitle(const std::string& title) {
@@ -118,7 +122,7 @@ int TreeViewTest::GetRowCount() {
}
TestNode* TreeViewTest::GetNodeByTitleImpl(TestNode* node,
- const string16& title) {
+ const base::string16& title) {
if (node->GetTitle() == title)
return node;
for (int i = 0; i < node->child_count(); ++i) {
@@ -131,7 +135,7 @@ TestNode* TreeViewTest::GetNodeByTitleImpl(TestNode* node,
std::string TreeViewTest::InternalNodeAsString(
TreeView::InternalNode* node) {
- std::string result = UTF16ToASCII(node->model_node()->GetTitle());
+ std::string result = base::UTF16ToASCII(node->model_node()->GetTitle());
if (node->is_expanded() && node->child_count()) {
result += " [";
for (int i = 0; i < node->child_count(); ++i) {
diff --git a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
index c1148c74e44..463ef7e3a05 100644
--- a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
+++ b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
@@ -57,13 +57,9 @@ void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
// Any unhandled keyboard/character messages should be defproced.
// This allows stuff like F10, etc to work correctly.
-#if defined(USE_AURA)
if (!event.os_event)
return;
const MSG& message(event.os_event->native_event());
-#else
- const MSG& message(event.os_event);
-#endif
DefWindowProc(message.hwnd, message.message, message.wParam, message.lParam);
}
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.cc b/chromium/ui/views/controls/webview/web_dialog_view.cc
index 7f88f022f55..ffb5cbafbde 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view.cc
@@ -12,22 +12,18 @@
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
#include "ui/web_dialogs/web_dialog_ui.h"
-#if defined(USE_AURA)
-#include "ui/events/event.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/native_widget_aura.h"
-#endif
-
using content::NativeWebKeyboardEvent;
using content::WebContents;
using content::WebUIMessageHandler;
@@ -46,7 +42,6 @@ WebDialogView::WebDialogView(
WebContentsHandler* handler)
: ClientView(NULL, NULL),
WebDialogWebContentsDelegate(context, handler),
- initialized_(false),
delegate_(delegate),
web_view_(new views::WebView(context)),
is_attempting_close_dialog_(false),
@@ -71,14 +66,14 @@ content::WebContents* WebDialogView::web_contents() {
////////////////////////////////////////////////////////////////////////////////
// WebDialogView, views::View implementation:
-gfx::Size WebDialogView::GetPreferredSize() {
+gfx::Size WebDialogView::GetPreferredSize() const {
gfx::Size out;
if (delegate_)
delegate_->GetDialogSize(&out);
return out;
}
-gfx::Size WebDialogView::GetMinimumSize() {
+gfx::Size WebDialogView::GetMinimumSize() const {
gfx::Size out;
if (delegate_)
delegate_->GetMinimumDialogSize(&out);
@@ -118,8 +113,7 @@ bool WebDialogView::CanClose() {
if (!is_attempting_close_dialog_) {
// Fire beforeunload event when user attempts to close the dialog.
is_attempting_close_dialog_ = true;
- web_view_->
- web_contents()->GetRenderViewHost()->FirePageBeforeUnload(false);
+ web_view_->web_contents()->DispatchBeforeUnload(false);
}
return false;
}
@@ -128,6 +122,8 @@ bool WebDialogView::CanClose() {
// WebDialogView, views::WidgetDelegate implementation:
bool WebDialogView::CanResize() const {
+ if (delegate_)
+ return delegate_->CanResizeDialog();
return true;
}
@@ -135,10 +131,10 @@ ui::ModalType WebDialogView::GetModalType() const {
return GetDialogModalType();
}
-string16 WebDialogView::GetWindowTitle() const {
+base::string16 WebDialogView::GetWindowTitle() const {
if (delegate_)
return delegate_->GetDialogTitle();
- return string16();
+ return base::string16();
}
std::string WebDialogView::GetWindowName() const {
@@ -188,7 +184,7 @@ ui::ModalType WebDialogView::GetDialogModalType() const {
return ui::MODAL_TYPE_NONE;
}
-string16 WebDialogView::GetDialogTitle() const {
+base::string16 WebDialogView::GetDialogTitle() const {
return GetWindowTitle();
}
@@ -282,23 +278,10 @@ void WebDialogView::MoveContents(WebContents* source, const gfx::Rect& pos) {
// they're all browser-specific. (This may change in the future.)
void WebDialogView::HandleKeyboardEvent(content::WebContents* source,
const NativeWebKeyboardEvent& event) {
-#if defined(USE_AURA)
if (!event.os_event)
return;
- ui::KeyEvent aura_event(event.os_event->native_event(), false);
- ui::EventHandler* event_handler =
- GetWidget()->native_widget()->GetEventHandler();
-
- DCHECK(event_handler);
- if (event_handler)
- event_handler->OnKeyEvent(&aura_event);
-#elif defined(OS_WIN)
- // Any unhandled keyboard/character messages should be defproced.
- // This allows stuff like F10, etc to work correctly.
- DefWindowProc(event.os_event.hwnd, event.os_event.message,
- event.os_event.wParam, event.os_event.lParam);
-#endif
+ GetWidget()->native_widget_private()->RepostNativeEvent(event.os_event);
}
void WebDialogView::CloseContents(WebContents* source) {
@@ -335,7 +318,8 @@ void WebDialogView::AddNewContents(content::WebContents* source,
was_blocked);
}
-void WebDialogView::LoadingStateChanged(content::WebContents* source) {
+void WebDialogView::LoadingStateChanged(content::WebContents* source,
+ bool to_different_document) {
if (delegate_)
delegate_->OnLoadingStateChanged(source);
}
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.h b/chromium/ui/views/controls/webview/web_dialog_view.h
index bb2eb395e52..2e69ad314ba 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.h
+++ b/chromium/ui/views/controls/webview/web_dialog_view.h
@@ -52,8 +52,8 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
content::WebContents* web_contents();
// Overridden from views::ClientView:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator)
OVERRIDE;
virtual void ViewHierarchyChanged(
@@ -63,7 +63,7 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// Overridden from views::WidgetDelegate:
virtual bool CanResize() const OVERRIDE;
virtual ui::ModalType GetModalType() const OVERRIDE;
- virtual string16 GetWindowTitle() const OVERRIDE;
+ virtual base::string16 GetWindowTitle() const OVERRIDE;
virtual std::string GetWindowName() const OVERRIDE;
virtual void WindowClosing() OVERRIDE;
virtual views::View* GetContentsView() OVERRIDE;
@@ -75,7 +75,7 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// Overridden from ui::WebDialogDelegate:
virtual ui::ModalType GetDialogModalType() const OVERRIDE;
- virtual string16 GetDialogTitle() const OVERRIDE;
+ virtual base::string16 GetDialogTitle() const OVERRIDE;
virtual GURL GetDialogContentURL() const OVERRIDE;
virtual void GetWebUIMessageHandlers(
std::vector<content::WebUIMessageHandler*>* handlers) const OVERRIDE;
@@ -110,7 +110,8 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
const gfx::Rect& initial_pos,
bool user_gesture,
bool* was_blocked) OVERRIDE;
- virtual void LoadingStateChanged(content::WebContents* source) OVERRIDE;
+ virtual void LoadingStateChanged(content::WebContents* source,
+ bool to_different_document) OVERRIDE;
virtual void BeforeUnloadFired(content::WebContents* tab,
bool proceed,
bool* proceed_to_fire_unload) OVERRIDE;
@@ -121,11 +122,6 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// Initializes the contents of the dialog.
void InitDialog();
- // Whether the view is initialized. That is, dialog accelerators is registered
- // and FreezeUpdates property is set to prevent WM from showing the window
- // until the property is removed.
- bool initialized_;
-
// This view is a delegate to the HTML content since it needs to get notified
// about when the dialog is closing. For all other actions (besides dialog
// closing) we delegate to the creator of this view, which we keep track of
@@ -142,11 +138,11 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// beforeunload event.
bool before_unload_fired_;
- // Whether the dialog is closed from WebUI in response to a "DialogClose"
+ // Whether the dialog is closed from WebUI in response to a "dialogClose"
// message.
bool closed_via_webui_;
- // A json string returned to WebUI from a "DialogClosed" message.
+ // A json string returned to WebUI from a "dialogClose" message.
std::string dialog_close_retval_;
// Whether CloseContents() has been called.
diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc
index f2ea02f48fb..21de7261231 100644
--- a/chromium/ui/views/controls/webview/webview.cc
+++ b/chromium/ui/views/controls/webview/webview.cc
@@ -10,10 +10,10 @@
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
#include "ipc/ipc_message.h"
-#include "ui/base/accessibility/accessibility_types.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/events/event.h"
#include "ui/views/accessibility/native_view_accessibility.h"
#include "ui/views/controls/native/native_view_host.h"
@@ -29,63 +29,51 @@ const char WebView::kViewClassName[] = "WebView";
// WebView, public:
WebView::WebView(content::BrowserContext* browser_context)
- : wcv_holder_(new NativeViewHost),
- web_contents_(NULL),
+ : holder_(new NativeViewHost()),
embed_fullscreen_widget_mode_enabled_(false),
is_embedding_fullscreen_widget_(false),
browser_context_(browser_context),
allow_accelerators_(false) {
- AddChildView(wcv_holder_);
+ AddChildView(holder_); // Takes ownership of |holder_|.
NativeViewAccessibility::RegisterWebView(this);
}
WebView::~WebView() {
+ SetWebContents(NULL); // Make sure all necessary tear-down takes place.
NativeViewAccessibility::UnregisterWebView(this);
}
content::WebContents* WebView::GetWebContents() {
- CreateWebContentsWithSiteInstance(NULL);
- return web_contents_;
-}
-
-void WebView::CreateWebContentsWithSiteInstance(
- content::SiteInstance* site_instance) {
- if (!web_contents_) {
- wc_owner_.reset(CreateWebContents(browser_context_, site_instance));
- web_contents_ = wc_owner_.get();
- web_contents_->SetDelegate(this);
- AttachWebContents();
+ if (!web_contents()) {
+ wc_owner_.reset(CreateWebContents(browser_context_));
+ wc_owner_->SetDelegate(this);
+ SetWebContents(wc_owner_.get());
}
+ return web_contents();
}
-void WebView::SetWebContents(content::WebContents* web_contents) {
- if (web_contents == web_contents_)
+void WebView::SetWebContents(content::WebContents* replacement) {
+ if (replacement == web_contents())
return;
DetachWebContents();
- if (wc_owner_ != web_contents)
+ WebContentsObserver::Observe(replacement);
+ // web_contents() now returns |replacement| from here onwards.
+ if (wc_owner_ != replacement)
wc_owner_.reset();
- web_contents_ = web_contents;
if (embed_fullscreen_widget_mode_enabled_) {
is_embedding_fullscreen_widget_ =
- web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
+ web_contents() && web_contents()->GetFullscreenRenderWidgetHostView();
} else {
- is_embedding_fullscreen_widget_ = false;
+ DCHECK(!is_embedding_fullscreen_widget_);
}
AttachWebContents();
+ NotifyMaybeTextInputClientChanged();
}
void WebView::SetEmbedFullscreenWidgetMode(bool enable) {
- bool should_be_embedded = enable;
- if (!embed_fullscreen_widget_mode_enabled_ && enable) {
- DCHECK(!is_embedding_fullscreen_widget_);
- embed_fullscreen_widget_mode_enabled_ = true;
- should_be_embedded =
- web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
- } else if (embed_fullscreen_widget_mode_enabled_ && !enable) {
- embed_fullscreen_widget_mode_enabled_ = false;
- }
- if (should_be_embedded != is_embedding_fullscreen_widget_)
- ReattachForFullscreenChange(should_be_embedded);
+ DCHECK(!web_contents())
+ << "Cannot change mode while a WebContents is attached.";
+ embed_fullscreen_widget_mode_enabled_ = enable;
}
void WebView::LoadInitialURL(const GURL& url) {
@@ -95,7 +83,7 @@ void WebView::LoadInitialURL(const GURL& url) {
}
void WebView::SetFastResize(bool fast_resize) {
- wcv_holder_->set_fast_resize(fast_resize);
+ holder_->set_fast_resize(fast_resize);
}
void WebView::OnWebContentsFocused(content::WebContents* web_contents) {
@@ -116,8 +104,68 @@ const char* WebView::GetClassName() const {
return kViewClassName;
}
+ui::TextInputClient* WebView::GetTextInputClient() {
+ // This function delegates the text input handling to the underlying
+ // content::RenderWidgetHostView. So when the underlying RWHV is destroyed or
+ // replaced with another one, we have to notify the FocusManager through
+ // FocusManager::OnTextInputClientChanged() that the focused TextInputClient
+ // needs to be updated.
+ if (switches::IsTextInputFocusManagerEnabled() &&
+ web_contents() && !web_contents()->IsBeingDestroyed()) {
+ content::RenderWidgetHostView* host_view =
+ is_embedding_fullscreen_widget_ ?
+ web_contents()->GetFullscreenRenderWidgetHostView() :
+ web_contents()->GetRenderWidgetHostView();
+ if (host_view)
+ return host_view->GetTextInputClient();
+ }
+ return NULL;
+}
+
void WebView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
- wcv_holder_->SetSize(bounds().size());
+ // In most cases, the holder is simply sized to fill this WebView's bounds.
+ // Only WebContentses that are in fullscreen mode and being screen-captured
+ // will engage the special layout/sizing behavior.
+ gfx::Rect holder_bounds(bounds().size());
+ if (!embed_fullscreen_widget_mode_enabled_ ||
+ !web_contents() ||
+ web_contents()->GetCapturerCount() == 0 ||
+ web_contents()->GetPreferredSize().IsEmpty() ||
+ !(is_embedding_fullscreen_widget_ ||
+ (web_contents()->GetDelegate() &&
+ web_contents()->GetDelegate()->
+ IsFullscreenForTabOrPending(web_contents())))) {
+ holder_->SetBoundsRect(holder_bounds);
+ return;
+ }
+
+ // Size the holder to the capture video resolution and center it. If this
+ // WebView is not large enough to contain the holder at the preferred size,
+ // scale down to fit (preserving aspect ratio).
+ const gfx::Size capture_size = web_contents()->GetPreferredSize();
+ if (capture_size.width() <= holder_bounds.width() &&
+ capture_size.height() <= holder_bounds.height()) {
+ // No scaling, just centering.
+ holder_bounds.ClampToCenteredSize(capture_size);
+ } else {
+ // Scale down, preserving aspect ratio, and center.
+ // TODO(miu): This is basically media::ComputeLetterboxRegion(), and it
+ // looks like others have written this code elsewhere. Let's considate
+ // into a shared function ui/gfx/geometry or around there.
+ const int64 x = static_cast<int64>(capture_size.width()) *
+ holder_bounds.height();
+ const int64 y = static_cast<int64>(capture_size.height()) *
+ holder_bounds.width();
+ if (y < x) {
+ holder_bounds.ClampToCenteredSize(gfx::Size(
+ holder_bounds.width(), static_cast<int>(y / capture_size.width())));
+ } else {
+ holder_bounds.ClampToCenteredSize(gfx::Size(
+ static_cast<int>(x / capture_size.height()), holder_bounds.height()));
+ }
+ }
+
+ holder_->SetBoundsRect(holder_bounds);
}
void WebView::ViewHierarchyChanged(
@@ -135,48 +183,48 @@ bool WebView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
// We'll first give the page a chance to process the key events. If it does
// not process them, they'll be returned to us and we'll treat them as
// accelerators then.
- return web_contents_ && !web_contents_->IsCrashed();
+ return web_contents() && !web_contents()->IsCrashed();
}
bool WebView::IsFocusable() const {
// We need to be focusable when our contents is not a view hierarchy, as
// clicking on the contents needs to focus us.
- return !!web_contents_;
+ return !!web_contents();
}
void WebView::OnFocus() {
- if (!web_contents_)
+ if (!web_contents())
return;
if (is_embedding_fullscreen_widget_) {
content::RenderWidgetHostView* const current_fs_view =
- web_contents_->GetFullscreenRenderWidgetHostView();
+ web_contents()->GetFullscreenRenderWidgetHostView();
if (current_fs_view)
current_fs_view->Focus();
} else {
- web_contents_->GetView()->Focus();
+ web_contents()->Focus();
}
}
void WebView::AboutToRequestFocusFromTabTraversal(bool reverse) {
- if (web_contents_)
- web_contents_->FocusThroughTabTraversal(reverse);
+ if (web_contents())
+ web_contents()->FocusThroughTabTraversal(reverse);
}
-void WebView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_GROUPING;
+void WebView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_GROUP;
}
gfx::NativeViewAccessible WebView::GetNativeViewAccessible() {
- if (web_contents_) {
+ if (web_contents()) {
content::RenderWidgetHostView* host_view =
- web_contents_->GetRenderWidgetHostView();
+ web_contents()->GetRenderWidgetHostView();
if (host_view)
return host_view->GetNativeViewAccessible();
}
return View::GetNativeViewAccessible();
}
-gfx::Size WebView::GetPreferredSize() {
+gfx::Size WebView::GetPreferredSize() const {
if (preferred_size_ == gfx::Size())
return View::GetPreferredSize();
else
@@ -189,7 +237,7 @@ gfx::Size WebView::GetPreferredSize() {
void WebView::WebContentsFocused(content::WebContents* web_contents) {
DCHECK(wc_owner_.get());
// The WebView is only the delegate of WebContentses it creates itself.
- OnWebContentsFocused(web_contents_);
+ OnWebContentsFocused(wc_owner_.get());
}
bool WebView::EmbedsFullscreenWidget() const {
@@ -200,19 +248,16 @@ bool WebView::EmbedsFullscreenWidget() const {
////////////////////////////////////////////////////////////////////////////////
// WebView, content::WebContentsObserver implementation:
+void WebView::RenderViewDeleted(content::RenderViewHost* render_view_host) {
+ NotifyMaybeTextInputClientChanged();
+}
+
void WebView::RenderViewHostChanged(content::RenderViewHost* old_host,
content::RenderViewHost* new_host) {
FocusManager* const focus_manager = GetFocusManager();
if (focus_manager && focus_manager->GetFocusedView() == this)
OnFocus();
-}
-
-void WebView::WebContentsDestroyed(content::WebContents* web_contents) {
- // We watch for destruction of WebContents that we host but do not own. If we
- // own a WebContents that is being destroyed, we're doing the destroying, so
- // we don't want to recursively tear it down while it's being torn down.
- if (!wc_owner_.get())
- SetWebContents(NULL);
+ NotifyMaybeTextInputClientChanged();
}
void WebView::DidShowFullscreenWidget(int routing_id) {
@@ -225,21 +270,27 @@ void WebView::DidDestroyFullscreenWidget(int routing_id) {
ReattachForFullscreenChange(false);
}
+void WebView::DidToggleFullscreenModeForTab(bool entered_fullscreen) {
+ if (embed_fullscreen_widget_mode_enabled_)
+ ReattachForFullscreenChange(entered_fullscreen);
+}
+
////////////////////////////////////////////////////////////////////////////////
// WebView, private:
void WebView::AttachWebContents() {
// Prevents attachment if the WebView isn't already in a Widget, or it's
// already attached.
- if (!GetWidget() || !web_contents_)
+ if (!GetWidget() || !web_contents())
return;
const gfx::NativeView view_to_attach = is_embedding_fullscreen_widget_ ?
- web_contents_->GetFullscreenRenderWidgetHostView()->GetNativeView() :
- web_contents_->GetView()->GetNativeView();
- if (wcv_holder_->native_view() == view_to_attach)
+ web_contents()->GetFullscreenRenderWidgetHostView()->GetNativeView() :
+ web_contents()->GetNativeView();
+ OnBoundsChanged(bounds());
+ if (holder_->native_view() == view_to_attach)
return;
- wcv_holder_->Attach(view_to_attach);
+ holder_->Attach(view_to_attach);
// The view will not be focused automatically when it is attached, so we need
// to pass on focus to it if the FocusManager thinks the view is focused. Note
@@ -248,58 +299,61 @@ void WebView::AttachWebContents() {
if (focus_manager && focus_manager->GetFocusedView() == this)
OnFocus();
- WebContentsObserver::Observe(web_contents_);
-
-#if defined(OS_WIN) && defined(USE_AURA)
+#if defined(OS_WIN)
if (!is_embedding_fullscreen_widget_) {
- web_contents_->SetParentNativeViewAccessible(
+ web_contents()->SetParentNativeViewAccessible(
parent()->GetNativeViewAccessible());
}
#endif
}
void WebView::DetachWebContents() {
- if (web_contents_) {
- wcv_holder_->Detach();
+ if (web_contents()) {
+ holder_->Detach();
#if defined(OS_WIN)
- if (!is_embedding_fullscreen_widget_) {
-#if !defined(USE_AURA)
- // TODO(beng): This should either not be necessary, or be done implicitly
- // by NativeViewHostWin on Detach(). As it stands, this is needed so that
- // the of the detached contents knows to tell the renderer it's been
- // hidden.
- //
- // Moving this out of here would also mean we wouldn't be potentially
- // calling member functions on a half-destroyed WebContents.
- ShowWindow(web_contents_->GetView()->GetNativeView(), SW_HIDE);
-#else
- web_contents_->SetParentNativeViewAccessible(NULL);
-#endif
- }
+ if (!is_embedding_fullscreen_widget_)
+ web_contents()->SetParentNativeViewAccessible(NULL);
#endif
}
- WebContentsObserver::Observe(NULL);
}
void WebView::ReattachForFullscreenChange(bool enter_fullscreen) {
- DetachWebContents();
- is_embedding_fullscreen_widget_ = enter_fullscreen &&
- web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
- AttachWebContents();
+ DCHECK(embed_fullscreen_widget_mode_enabled_);
+ const bool web_contents_has_separate_fs_widget =
+ web_contents() && web_contents()->GetFullscreenRenderWidgetHostView();
+ if (is_embedding_fullscreen_widget_ || web_contents_has_separate_fs_widget) {
+ // Shutting down or starting up the embedding of the separate fullscreen
+ // widget. Need to detach and re-attach to a different native view.
+ DetachWebContents();
+ is_embedding_fullscreen_widget_ =
+ enter_fullscreen && web_contents_has_separate_fs_widget;
+ AttachWebContents();
+ } else {
+ // Entering or exiting "non-Flash" fullscreen mode, where the native view is
+ // the same. So, do not change attachment.
+ OnBoundsChanged(bounds());
+ }
+ NotifyMaybeTextInputClientChanged();
+}
+
+void WebView::NotifyMaybeTextInputClientChanged() {
+ // Update the TextInputClient as needed; see GetTextInputClient().
+ FocusManager* const focus_manager = GetFocusManager();
+ if (focus_manager)
+ focus_manager->OnTextInputClientChanged(this);
}
content::WebContents* WebView::CreateWebContents(
- content::BrowserContext* browser_context,
- content::SiteInstance* site_instance) {
+ content::BrowserContext* browser_context) {
content::WebContents* contents = NULL;
if (ViewsDelegate::views_delegate) {
contents = ViewsDelegate::views_delegate->CreateWebContents(
- browser_context, site_instance);
+ browser_context, NULL);
}
if (!contents) {
content::WebContents::CreateParams create_params(
- browser_context, site_instance);
+ browser_context, NULL);
return content::WebContents::Create(create_params);
}
diff --git a/chromium/ui/views/controls/webview/webview.gyp b/chromium/ui/views/controls/webview/webview.gyp
index 6d74ef2dfad..39d40201d80 100644
--- a/chromium/ui/views/controls/webview/webview.gyp
+++ b/chromium/ui/views/controls/webview/webview.gyp
@@ -17,9 +17,10 @@
'../../../../content/content.gyp:content_browser',
'../../../../skia/skia.gyp:skia',
'../../../../url/url.gyp:url_lib',
+ '../../../base/ui_base.gyp:ui_base',
'../../../events/events.gyp:events',
'../../../gfx/gfx.gyp:gfx',
- '../../../ui.gyp:ui',
+ '../../../gfx/gfx.gyp:gfx_geometry',
'../../../web_dialogs/web_dialogs.gyp:web_dialogs',
'../../views.gyp:views',
],
diff --git a/chromium/ui/views/controls/webview/webview.h b/chromium/ui/views/controls/webview/webview.h
index ae789be2aaa..5cbb8874286 100644
--- a/chromium/ui/views/controls/webview/webview.h
+++ b/chromium/ui/views/controls/webview/webview.h
@@ -13,14 +13,24 @@
#include "ui/views/controls/webview/webview_export.h"
#include "ui/views/view.h"
-namespace content {
-class SiteInstance;
-}
-
namespace views {
class NativeViewHost;
+// Provides a view of a WebContents instance. WebView can be used standalone,
+// creating and displaying an internally-owned WebContents; or within a full
+// browser where the browser swaps its own WebContents instances in/out (e.g.,
+// for browser tabs).
+//
+// WebView creates and owns a single child view, a NativeViewHost, which will
+// hold and display the native view provided by a WebContents.
+//
+// EmbedFullscreenWidgetMode: When enabled, WebView will observe for WebContents
+// fullscreen changes and automatically swap the normal native view with the
+// fullscreen native view (if different). In addition, if the WebContents is
+// being screen-captured, the view will be centered within WebView, sized to
+// the aspect ratio of the capture video resolution, and scaling will be avoided
+// whenever possible.
class WEBVIEW_EXPORT WebView : public View,
public content::WebContentsDelegate,
public content::WebContentsObserver {
@@ -34,10 +44,6 @@ class WEBVIEW_EXPORT WebView : public View,
// WebView owns this implicitly created WebContents.
content::WebContents* GetWebContents();
- // Creates a WebContents if none is yet assocaited with this WebView, with the
- // specified site instance. The WebView owns this WebContents.
- void CreateWebContentsWithSiteInstance(content::SiteInstance* site_instance);
-
// WebView does not assume ownership of WebContents set via this method, only
// those it implicitly creates via GetWebContents() above.
void SetWebContents(content::WebContents* web_contents);
@@ -48,7 +54,9 @@ class WEBVIEW_EXPORT WebView : public View,
// widget or restore the normal WebContentsView.
void SetEmbedFullscreenWidgetMode(bool mode);
- content::WebContents* web_contents() { return web_contents_; }
+ content::WebContents* web_contents() const {
+ return content::WebContentsObserver::web_contents();
+ }
content::BrowserContext* browser_context() { return browser_context_; }
@@ -86,8 +94,9 @@ class WEBVIEW_EXPORT WebView : public View,
// Overridden from View:
virtual const char* GetClassName() const OVERRIDE;
+ virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
- private:
+ protected:
// Overridden from View:
virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
virtual void ViewHierarchyChanged(
@@ -97,44 +106,48 @@ class WEBVIEW_EXPORT WebView : public View,
virtual bool IsFocusable() const OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void AboutToRequestFocusFromTabTraversal(bool reverse) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Overridden from content::WebContentsDelegate:
virtual void WebContentsFocused(content::WebContents* web_contents) OVERRIDE;
virtual bool EmbedsFullscreenWidget() const OVERRIDE;
// Overridden from content::WebContentsObserver:
+ virtual void RenderViewDeleted(
+ content::RenderViewHost* render_view_host) OVERRIDE;
virtual void RenderViewHostChanged(
content::RenderViewHost* old_host,
content::RenderViewHost* new_host) OVERRIDE;
- virtual void WebContentsDestroyed(
- content::WebContents* web_contents) OVERRIDE;
virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE;
virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE;
+ virtual void DidToggleFullscreenModeForTab(bool entered_fullscreen) OVERRIDE;
// Workaround for MSVC++ linker bug/feature that requires
// instantiation of the inline IPC::Listener methods in all translation units.
virtual void OnChannelConnected(int32 peer_id) OVERRIDE {}
virtual void OnChannelError() OVERRIDE {}
+ virtual void OnBadMessageReceived(const IPC::Message& message) OVERRIDE {}
+ private:
void AttachWebContents();
void DetachWebContents();
void ReattachForFullscreenChange(bool enter_fullscreen);
+ void NotifyMaybeTextInputClientChanged();
// Create a regular or test web contents (based on whether we're running
// in a unit test or not).
content::WebContents* CreateWebContents(
- content::BrowserContext* browser_context,
- content::SiteInstance* site_instance);
+ content::BrowserContext* browser_context);
- NativeViewHost* wcv_holder_;
+ NativeViewHost* const holder_;
+ // Non-NULL if |web_contents()| was created and is owned by this WebView.
scoped_ptr<content::WebContents> wc_owner_;
- content::WebContents* web_contents_;
// When true, WebView auto-embeds fullscreen widgets as a child view.
bool embed_fullscreen_widget_mode_enabled_;
// Set to true while WebView is embedding a fullscreen widget view as a child
- // view instead of the normal WebContentsView render view.
+ // view instead of the normal WebContentsView render view. Note: This will be
+ // false in the case of non-Flash fullscreen.
bool is_embedding_fullscreen_widget_;
content::BrowserContext* browser_context_;
bool allow_accelerators_;
diff --git a/chromium/ui/views/controls/webview/webview_interactive_uitest.cc b/chromium/ui/views/controls/webview/webview_interactive_uitest.cc
new file mode 100644
index 00000000000..f1179b83eab
--- /dev/null
+++ b/chromium/ui/views/controls/webview/webview_interactive_uitest.cc
@@ -0,0 +1,82 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/webview/webview.h"
+
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/views/test/webview_test_helper.h"
+#include "ui/views/test/widget_test.h"
+
+namespace {
+
+class WebViewInteractiveUiTest : public views::test::WidgetTest {
+ public:
+ WebViewInteractiveUiTest()
+ : ui_thread_(content::BrowserThread::UI, base::MessageLoop::current()) {}
+
+ virtual void SetUp() OVERRIDE {
+ gfx::GLSurface::InitializeOneOffForTests();
+ WidgetTest::SetUp();
+ }
+
+ protected:
+ content::BrowserContext* browser_context() { return &browser_context_; }
+
+ private:
+ content::TestBrowserContext browser_context_;
+ views::WebViewTestHelper webview_test_helper_;
+ content::TestBrowserThread ui_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebViewInteractiveUiTest);
+};
+
+TEST_F(WebViewInteractiveUiTest, TextInputClientIsUpToDate) {
+ // WebViewInteractiveUiTest.TextInputClientIsUpToDate needs
+ // kEnableTextInputFocusManager flag to be enabled.
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ cmd_line->AppendSwitch(switches::kEnableTextInputFocusManager);
+
+ // Create a top level widget and a webview as its content.
+ views::Widget* widget = CreateTopLevelFramelessPlatformWidget();
+ views::WebView* webview = new views::WebView(browser_context());
+ widget->SetContentsView(webview);
+ widget->Show();
+ webview->RequestFocus();
+
+ ui::TextInputFocusManager* text_input_focus_manager =
+ ui::TextInputFocusManager::GetInstance();
+ const ui::TextInputClient* null_text_input_client = NULL;
+ EXPECT_EQ(null_text_input_client, webview->GetTextInputClient());
+ EXPECT_EQ(text_input_focus_manager->GetFocusedTextInputClient(),
+ webview->GetTextInputClient());
+
+ // Case 1: Creates a new WebContents.
+ webview->GetWebContents();
+ webview->RequestFocus();
+ ui::TextInputClient* client1 = webview->GetTextInputClient();
+ EXPECT_NE(null_text_input_client, client1);
+ EXPECT_EQ(text_input_focus_manager->GetFocusedTextInputClient(), client1);
+
+ // Case 2: Replaces a WebContents by SetWebContents().
+ content::WebContents::CreateParams params(browser_context());
+ scoped_ptr<content::WebContents> web_contents(
+ content::WebContents::Create(params));
+ webview->SetWebContents(web_contents.get());
+ ui::TextInputClient* client2 = webview->GetTextInputClient();
+ EXPECT_NE(null_text_input_client, client2);
+ EXPECT_EQ(text_input_focus_manager->GetFocusedTextInputClient(), client2);
+ EXPECT_NE(client1, client2);
+
+ widget->Close();
+ RunPendingMessages();
+}
+
+} // namespace
diff --git a/chromium/ui/views/controls/webview/webview_tests.gyp b/chromium/ui/views/controls/webview/webview_tests.gyp
new file mode 100644
index 00000000000..0adc5c2befc
--- /dev/null
+++ b/chromium/ui/views/controls/webview/webview_tests.gyp
@@ -0,0 +1,38 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'webview_test_support',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../../../base/base.gyp:base',
+ '../../../../content/content.gyp:content',
+ '../../../../content/content_shell_and_tests.gyp:test_support_content',
+ '../../../../ipc/ipc.gyp:test_support_ipc',
+ '../../../../skia/skia.gyp:skia',
+ '../../../../testing/gtest.gyp:gtest',
+ '../../../aura/aura.gyp:aura',
+ '../../../base/ui_base.gyp:ui_base',
+ '../../../events/events.gyp:events',
+ '../../../gfx/gfx.gyp:gfx',
+ '../../../gfx/gfx.gyp:gfx_geometry',
+ '../../views.gyp:views',
+ '../../views.gyp:views_test_support',
+ 'webview.gyp:webview',
+ ],
+ 'include_dirs': [
+ '../../../..',
+ ],
+ 'sources': [
+ '../../test/webview_test_helper.cc',
+ '../../test/webview_test_helper.h',
+ ],
+ },
+ ],
+}