summaryrefslogtreecommitdiffstats
path: root/ui/views
diff options
context:
space:
mode:
Diffstat (limited to 'ui/views')
-rw-r--r--ui/views/accessibility/native_view_accessibility_win.h2
-rw-r--r--ui/views/animation/bounds_animator.cc2
-rw-r--r--ui/views/animation/bounds_animator_unittest.cc2
-rw-r--r--ui/views/bubble/border_contents_view.h2
-rw-r--r--ui/views/controls/button/button.h2
-rw-r--r--ui/views/controls/combobox/combobox.h2
-rw-r--r--ui/views/controls/combobox/native_combobox_views.h2
-rw-r--r--ui/views/controls/focusable_border.h2
-rw-r--r--ui/views/controls/image_view.h2
-rw-r--r--ui/views/controls/label.h2
-rw-r--r--ui/views/controls/menu/menu_item_view.h2
-rw-r--r--ui/views/controls/menu/menu_scroll_view_container.h2
-rw-r--r--ui/views/controls/menu/menu_separator.h2
-rw-r--r--ui/views/controls/menu/submenu_view.h2
-rw-r--r--ui/views/controls/message_box_view.h2
-rw-r--r--ui/views/controls/native/native_view_host.h2
-rw-r--r--ui/views/controls/native_control.h2
-rw-r--r--ui/views/controls/progress_bar.h2
-rw-r--r--ui/views/controls/resize_area.h2
-rw-r--r--ui/views/controls/scrollbar/base_scroll_bar_thumb.h2
-rw-r--r--ui/views/controls/scrollbar/native_scroll_bar.h2
-rw-r--r--ui/views/controls/scrollbar/native_scroll_bar_views.h2
-rw-r--r--ui/views/controls/scrollbar/scroll_bar.h2
-rw-r--r--ui/views/controls/separator.h2
-rw-r--r--ui/views/controls/single_split_view.h2
-rw-r--r--ui/views/controls/tabbed_pane/native_tabbed_pane_views.h2
-rw-r--r--ui/views/controls/tabbed_pane/tabbed_pane.h2
-rw-r--r--ui/views/controls/table/table_view2.h2
-rw-r--r--ui/views/controls/textfield/native_textfield_views.h2
-rw-r--r--ui/views/controls/textfield/textfield.h2
-rw-r--r--ui/views/controls/throbber.h2
-rw-r--r--ui/views/debug_utils.cc2
-rw-r--r--ui/views/events/event.cc2
-rw-r--r--ui/views/examples/button_example.cc2
-rw-r--r--ui/views/examples/example_base.cc2
-rw-r--r--ui/views/examples/link_example.cc2
-rw-r--r--ui/views/examples/menu_example.cc2
-rw-r--r--ui/views/examples/message_box_example.cc2
-rw-r--r--ui/views/examples/native_widget_views_example.cc2
-rw-r--r--ui/views/examples/progress_bar_example.cc2
-rw-r--r--ui/views/examples/radio_button_example.cc2
-rw-r--r--ui/views/examples/scroll_view_example.cc2
-rw-r--r--ui/views/examples/text_example.cc2
-rw-r--r--ui/views/examples/textfield_example.cc2
-rw-r--r--ui/views/examples/throbber_example.cc2
-rw-r--r--ui/views/examples/widget_example.cc2
-rw-r--r--ui/views/focus/accelerator_handler_gtk_unittest.cc2
-rw-r--r--ui/views/focus/external_focus_tracker.cc2
-rw-r--r--ui/views/focus/focus_manager.cc2
-rw-r--r--ui/views/focus/focus_search.cc2
-rw-r--r--ui/views/focus/focus_search.h2
-rw-r--r--ui/views/focus/view_storage.h2
-rw-r--r--ui/views/ime/input_method_base.cc2
-rw-r--r--ui/views/ime/input_method_gtk.h2
-rw-r--r--ui/views/ime/input_method_ibus.h2
-rw-r--r--ui/views/ime/input_method_win.h2
-rw-r--r--ui/views/ime/mock_input_method.h2
-rw-r--r--ui/views/layout/box_layout.cc2
-rw-r--r--ui/views/layout/box_layout_unittest.cc2
-rw-r--r--ui/views/layout/fill_layout.h2
-rw-r--r--ui/views/layout/grid_layout.cc2
-rw-r--r--ui/views/layout/grid_layout.h2
-rw-r--r--ui/views/layout/grid_layout_unittest.cc2
-rw-r--r--ui/views/layout/layout_manager.cc2
-rw-r--r--ui/views/mouse_watcher.cc2
-rw-r--r--ui/views/touchui/gesture_manager.cc2
-rw-r--r--ui/views/touchui/gesture_manager.h2
-rw-r--r--ui/views/touchui/touch_selection_controller.h2
-rw-r--r--ui/views/touchui/touch_selection_controller_impl.h2
-rw-r--r--ui/views/view.cc2061
-rw-r--r--ui/views/view.h1440
-rw-r--r--ui/views/view_aura.cc37
-rw-r--r--ui/views/view_gtk.cc39
-rw-r--r--ui/views/view_unittest.cc3068
-rw-r--r--ui/views/view_win.cc36
-rw-r--r--ui/views/widget/drop_helper.cc2
-rw-r--r--ui/views/widget/native_widget_test_utils_aura.cc2
-rw-r--r--ui/views/widget/native_widget_test_utils_gtk.cc2
-rw-r--r--ui/views/widget/native_widget_test_utils_win.cc2
-rw-r--r--ui/views/widget/native_widget_unittest.cc2
-rw-r--r--ui/views/widget/root_view.h2
-rw-r--r--ui/views/widget/tooltip_manager_gtk.cc2
-rw-r--r--ui/views/widget/tooltip_manager_views.cc2
-rw-r--r--ui/views/widget/tooltip_manager_views.h2
-rw-r--r--ui/views/widget/tooltip_manager_win.cc2
-rw-r--r--ui/views/widget/widget_delegate.cc2
-rw-r--r--ui/views/widget/widget_delegate.h2
-rw-r--r--ui/views/window/client_view.h2
-rw-r--r--ui/views/window/non_client_view.h2
89 files changed, 6764 insertions, 83 deletions
diff --git a/ui/views/accessibility/native_view_accessibility_win.h b/ui/views/accessibility/native_view_accessibility_win.h
index e017050..51254d9 100644
--- a/ui/views/accessibility/native_view_accessibility_win.h
+++ b/ui/views/accessibility/native_view_accessibility_win.h
@@ -15,7 +15,7 @@
#include "third_party/iaccessible2/ia2_api_all.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/views/controls/native/native_view_host.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace ui {
enum TextBoundaryDirection;
diff --git a/ui/views/animation/bounds_animator.cc b/ui/views/animation/bounds_animator.cc
index d656d0a..2e4b0c1 100644
--- a/ui/views/animation/bounds_animator.cc
+++ b/ui/views/animation/bounds_animator.cc
@@ -7,7 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "ui/base/animation/animation_container.h"
#include "ui/base/animation/slide_animation.h"
-#include "views/view.h"
+#include "ui/views/view.h"
// Duration in milliseconds for animations.
static const int kAnimationDuration = 200;
diff --git a/ui/views/animation/bounds_animator_unittest.cc b/ui/views/animation/bounds_animator_unittest.cc
index d030ba1..bf1f08c 100644
--- a/ui/views/animation/bounds_animator_unittest.cc
+++ b/ui/views/animation/bounds_animator_unittest.cc
@@ -6,7 +6,7 @@
#include "ui/base/animation/slide_animation.h"
#include "ui/base/animation/test_animation_delegate.h"
#include "ui/views/animation/bounds_animator.h"
-#include "views/view.h"
+#include "ui/views/view.h"
using views::BoundsAnimator;
using ui::Animation;
diff --git a/ui/views/bubble/border_contents_view.h b/ui/views/bubble/border_contents_view.h
index e30ba19..2e86662 100644
--- a/ui/views/bubble/border_contents_view.h
+++ b/ui/views/bubble/border_contents_view.h
@@ -8,7 +8,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "ui/views/bubble/bubble_border.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/button/button.h b/ui/views/controls/button/button.h
index 41aba33..7cba9d1 100644
--- a/ui/views/controls/button/button.h
+++ b/ui/views/controls/button/button.h
@@ -6,7 +6,7 @@
#define UI_VIEWS_CONTROLS_BUTTON_BUTTON_H_
#pragma once
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/combobox/combobox.h b/ui/views/controls/combobox/combobox.h
index dbd62db..a6f7e35 100644
--- a/ui/views/controls/combobox/combobox.h
+++ b/ui/views/controls/combobox/combobox.h
@@ -10,7 +10,7 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/views/controls/combobox/native_combobox_wrapper.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace ui {
class ComboboxModel;
diff --git a/ui/views/controls/combobox/native_combobox_views.h b/ui/views/controls/combobox/native_combobox_views.h
index 784539e..61c70a3 100644
--- a/ui/views/controls/combobox/native_combobox_views.h
+++ b/ui/views/controls/combobox/native_combobox_views.h
@@ -8,7 +8,7 @@
#include "ui/views/controls/combobox/native_combobox_wrapper.h"
#include "ui/views/controls/menu/menu_delegate.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace gfx {
class Canvas;
diff --git a/ui/views/controls/focusable_border.h b/ui/views/controls/focusable_border.h
index 098809b..903bb61 100644
--- a/ui/views/controls/focusable_border.h
+++ b/ui/views/controls/focusable_border.h
@@ -8,8 +8,8 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "ui/views/view.h"
#include "views/border.h"
-#include "views/view.h"
namespace gfx {
class Canvas;
diff --git a/ui/views/controls/image_view.h b/ui/views/controls/image_view.h
index 1149c8d..8827d4e 100644
--- a/ui/views/controls/image_view.h
+++ b/ui/views/controls/image_view.h
@@ -7,7 +7,7 @@
#pragma once
#include "third_party/skia/include/core/SkBitmap.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace gfx {
class Canvas;
diff --git a/ui/views/controls/label.h b/ui/views/controls/label.h
index 4f0d6c2..e2c15cc 100644
--- a/ui/views/controls/label.h
+++ b/ui/views/controls/label.h
@@ -14,7 +14,7 @@
#include "googleurl/src/gurl.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/font.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/menu/menu_item_view.h b/ui/views/controls/menu/menu_item_view.h
index 28481e8..91da31b 100644
--- a/ui/views/controls/menu/menu_item_view.h
+++ b/ui/views/controls/menu/menu_item_view.h
@@ -14,7 +14,7 @@
#include "base/string16.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "views/view.h"
+#include "ui/views/view.h"
#if defined(OS_WIN)
#include <windows.h>
diff --git a/ui/views/controls/menu/menu_scroll_view_container.h b/ui/views/controls/menu/menu_scroll_view_container.h
index a19b73a..234c8f1 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/ui/views/controls/menu/menu_scroll_view_container.h
@@ -6,7 +6,7 @@
#define UI_VIEWS_CONTROLS_MENU_MENU_SCROLL_VIEW_CONTAINER_H_
#pragma once
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/menu/menu_separator.h b/ui/views/controls/menu/menu_separator.h
index 4e968a3..d404ddb 100644
--- a/ui/views/controls/menu/menu_separator.h
+++ b/ui/views/controls/menu/menu_separator.h
@@ -7,7 +7,7 @@
#pragma once
#include "base/compiler_specific.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/menu/submenu_view.h b/ui/views/controls/menu/submenu_view.h
index 693a538..d4d0497 100644
--- a/ui/views/controls/menu/submenu_view.h
+++ b/ui/views/controls/menu/submenu_view.h
@@ -10,7 +10,7 @@
#include "base/compiler_specific.h"
#include "ui/views/controls/menu/menu_delegate.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/message_box_view.h b/ui/views/controls/message_box_view.h
index 64e1f27..cd81e40 100644
--- a/ui/views/controls/message_box_view.h
+++ b/ui/views/controls/message_box_view.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/string16.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/native/native_view_host.h b/ui/views/controls/native/native_view_host.h
index 674222b..52575f0 100644
--- a/ui/views/controls/native/native_view_host.h
+++ b/ui/views/controls/native/native_view_host.h
@@ -9,7 +9,7 @@
#include <string>
#include "ui/gfx/native_widget_types.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/native_control.h b/ui/views/controls/native_control.h
index ba419c1..f439d3f 100644
--- a/ui/views/controls/native_control.h
+++ b/ui/views/controls/native_control.h
@@ -9,7 +9,7 @@
#include <windows.h>
#include "ui/base/keycodes/keyboard_codes.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/progress_bar.h b/ui/views/controls/progress_bar.h
index 02674de..10ce757 100644
--- a/ui/views/controls/progress_bar.h
+++ b/ui/views/controls/progress_bar.h
@@ -8,7 +8,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/resize_area.h b/ui/views/controls/resize_area.h
index 1cebd9d..57c65ca 100644
--- a/ui/views/controls/resize_area.h
+++ b/ui/views/controls/resize_area.h
@@ -8,7 +8,7 @@
#include <string>
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/scrollbar/base_scroll_bar_thumb.h b/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
index f015478..c7daf93 100644
--- a/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
+++ b/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
@@ -9,7 +9,7 @@
#include "ui/gfx/size.h"
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/scrollbar/scroll_bar.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace gfx {
class Canvas;
diff --git a/ui/views/controls/scrollbar/native_scroll_bar.h b/ui/views/controls/scrollbar/native_scroll_bar.h
index 73892fc..c5a9776 100644
--- a/ui/views/controls/scrollbar/native_scroll_bar.h
+++ b/ui/views/controls/scrollbar/native_scroll_bar.h
@@ -11,7 +11,7 @@
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "ui/views/controls/scrollbar/scroll_bar.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/scrollbar/native_scroll_bar_views.h b/ui/views/controls/scrollbar/native_scroll_bar_views.h
index 6e26487d..136338c 100644
--- a/ui/views/controls/scrollbar/native_scroll_bar_views.h
+++ b/ui/views/controls/scrollbar/native_scroll_bar_views.h
@@ -12,7 +12,7 @@
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/scrollbar/base_scroll_bar.h"
#include "ui/views/controls/scrollbar/native_scroll_bar_wrapper.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace gfx {
class Canvas;
diff --git a/ui/views/controls/scrollbar/scroll_bar.h b/ui/views/controls/scrollbar/scroll_bar.h
index 6e83ffa..39263d6 100644
--- a/ui/views/controls/scrollbar/scroll_bar.h
+++ b/ui/views/controls/scrollbar/scroll_bar.h
@@ -8,7 +8,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "views/view.h"
+#include "ui/views/view.h"
#include "views/views_export.h"
namespace views {
diff --git a/ui/views/controls/separator.h b/ui/views/controls/separator.h
index f47d238..44df432 100644
--- a/ui/views/controls/separator.h
+++ b/ui/views/controls/separator.h
@@ -8,7 +8,7 @@
#include <string>
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/single_split_view.h b/ui/views/controls/single_split_view.h
index c3f2bc3..6c3cd97 100644
--- a/ui/views/controls/single_split_view.h
+++ b/ui/views/controls/single_split_view.h
@@ -7,7 +7,7 @@
#pragma once
#include "base/gtest_prod_util.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/tabbed_pane/native_tabbed_pane_views.h b/ui/views/controls/tabbed_pane/native_tabbed_pane_views.h
index 87a9291..5ab456a 100644
--- a/ui/views/controls/tabbed_pane/native_tabbed_pane_views.h
+++ b/ui/views/controls/tabbed_pane/native_tabbed_pane_views.h
@@ -9,7 +9,7 @@
#include <vector>
#include "ui/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.h b/ui/views/controls/tabbed_pane/tabbed_pane.h
index 97a9d63..4150662 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.h
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.h
@@ -9,7 +9,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/string16.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/controls/table/table_view2.h b/ui/views/controls/table/table_view2.h
index d4f4e86..5ba5c1b 100644
--- a/ui/views/controls/table/table_view2.h
+++ b/ui/views/controls/table/table_view2.h
@@ -16,7 +16,7 @@
#include "ui/gfx/canvas.h"
#include "ui/views/controls/table/native_table_wrapper.h"
#include "ui/views/controls/table/table_view.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace ui {
struct TableColumn;
diff --git a/ui/views/controls/textfield/native_textfield_views.h b/ui/views/controls/textfield/native_textfield_views.h
index a9cfbb8..8ff590c 100644
--- a/ui/views/controls/textfield/native_textfield_views.h
+++ b/ui/views/controls/textfield/native_textfield_views.h
@@ -16,8 +16,8 @@
#include "ui/views/controls/textfield/textfield_views_model.h"
#include "ui/views/drag_controller.h"
#include "ui/views/touchui/touch_selection_controller.h"
+#include "ui/views/view.h"
#include "views/border.h"
-#include "views/view.h"
namespace base {
class Time;
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index abdd590..5ff542d 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -19,7 +19,7 @@
#include "ui/gfx/font.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/controls/textfield/native_textfield_wrapper.h"
-#include "views/view.h"
+#include "ui/views/view.h"
#if !defined(OS_LINUX)
#include "base/logging.h"
diff --git a/ui/views/controls/throbber.h b/ui/views/controls/throbber.h
index e40828f..28ead31 100644
--- a/ui/views/controls/throbber.h
+++ b/ui/views/controls/throbber.h
@@ -10,7 +10,7 @@
#include "base/compiler_specific.h"
#include "base/time.h"
#include "base/timer.h"
-#include "views/view.h"
+#include "ui/views/view.h"
class SkBitmap;
diff --git a/ui/views/debug_utils.cc b/ui/views/debug_utils.cc
index 23a75d2..9298122 100644
--- a/ui/views/debug_utils.cc
+++ b/ui/views/debug_utils.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "base/utf_string_conversions.h"
-#include "views/view.h"
+#include "ui/views/view.h"
#ifndef NDEBUG
#include <iostream>
diff --git a/ui/views/events/event.cc b/ui/views/events/event.cc
index 1fd17ec..5f2d320 100644
--- a/ui/views/events/event.cc
+++ b/ui/views/events/event.cc
@@ -6,8 +6,8 @@
#include "base/logging.h"
#include "ui/base/keycodes/keyboard_code_conversion.h"
+#include "ui/views/view.h"
#include "ui/views/widget/root_view.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/examples/button_example.cc b/ui/views/examples/button_example.cc
index ca15c36..6a16864 100644
--- a/ui/views/examples/button_example.cc
+++ b/ui/views/examples/button_example.cc
@@ -9,7 +9,7 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/layout/fill_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/example_base.cc b/ui/views/examples/example_base.cc
index f86278e..1336c0c 100644
--- a/ui/views/examples/example_base.cc
+++ b/ui/views/examples/example_base.cc
@@ -9,7 +9,7 @@
#include "base/compiler_specific.h"
#include "base/stringprintf.h"
#include "ui/views/examples/examples_window.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/link_example.cc b/ui/views/examples/link_example.cc
index 183badc..4882aaa 100644
--- a/ui/views/examples/link_example.cc
+++ b/ui/views/examples/link_example.cc
@@ -7,7 +7,7 @@
#include "base/utf_string_conversions.h"
#include "ui/views/controls/link.h"
#include "ui/views/layout/fill_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/menu_example.cc b/ui/views/examples/menu_example.cc
index db27e07..50640c3 100644
--- a/ui/views/examples/menu_example.cc
+++ b/ui/views/examples/menu_example.cc
@@ -13,7 +13,7 @@
#include "ui/views/controls/menu/menu_2.h"
#include "ui/views/controls/menu/view_menu_delegate.h"
#include "ui/views/layout/fill_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/message_box_example.cc b/ui/views/examples/message_box_example.cc
index 942f22b..3bb6eb7 100644
--- a/ui/views/examples/message_box_example.cc
+++ b/ui/views/examples/message_box_example.cc
@@ -7,7 +7,7 @@
#include "base/utf_string_conversions.h"
#include "ui/views/controls/message_box_view.h"
#include "ui/views/layout/grid_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/native_widget_views_example.cc b/ui/views/examples/native_widget_views_example.cc
index c42bc72..783ca4a 100644
--- a/ui/views/examples/native_widget_views_example.cc
+++ b/ui/views/examples/native_widget_views_example.cc
@@ -9,9 +9,9 @@
#include "ui/views/controls/button/text_button.h"
#include "ui/views/examples/example_base.h"
#include "ui/views/test/test_views_delegate.h"
+#include "ui/views/view.h"
#include "ui/views/widget/native_widget_views.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace examples {
diff --git a/ui/views/examples/progress_bar_example.cc b/ui/views/examples/progress_bar_example.cc
index f355007..3a93bc5 100644
--- a/ui/views/examples/progress_bar_example.cc
+++ b/ui/views/examples/progress_bar_example.cc
@@ -8,7 +8,7 @@
#include "ui/views/controls/button/text_button.h"
#include "ui/views/controls/progress_bar.h"
#include "ui/views/layout/grid_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace {
diff --git a/ui/views/examples/radio_button_example.cc b/ui/views/examples/radio_button_example.cc
index 315793a..42a6ea9 100644
--- a/ui/views/examples/radio_button_example.cc
+++ b/ui/views/examples/radio_button_example.cc
@@ -8,7 +8,7 @@
#include "base/utf_string_conversions.h"
#include "ui/views/controls/button/text_button.h"
#include "ui/views/layout/grid_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/scroll_view_example.cc b/ui/views/examples/scroll_view_example.cc
index 5247640..a0f293f 100644
--- a/ui/views/examples/scroll_view_example.cc
+++ b/ui/views/examples/scroll_view_example.cc
@@ -8,7 +8,7 @@
#include "base/utf_string_conversions.h"
#include "ui/views/controls/button/radio_button.h"
#include "ui/views/layout/grid_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/text_example.cc b/ui/views/examples/text_example.cc
index d51b1d5..c167d00 100644
--- a/ui/views/examples/text_example.cc
+++ b/ui/views/examples/text_example.cc
@@ -13,7 +13,7 @@
#include "ui/views/controls/label.h"
#include "ui/views/examples/example_combobox_model.h"
#include "ui/views/layout/grid_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace {
diff --git a/ui/views/examples/textfield_example.cc b/ui/views/examples/textfield_example.cc
index 780cd81..7b4986c 100644
--- a/ui/views/examples/textfield_example.cc
+++ b/ui/views/examples/textfield_example.cc
@@ -10,7 +10,7 @@
#include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/grid_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/throbber_example.cc b/ui/views/examples/throbber_example.cc
index a3af5cf..913d079 100644
--- a/ui/views/examples/throbber_example.cc
+++ b/ui/views/examples/throbber_example.cc
@@ -6,7 +6,7 @@
#include "ui/views/controls/throbber.h"
#include "ui/views/layout/fill_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/examples/widget_example.cc b/ui/views/examples/widget_example.cc
index 76ccb49..11d6504 100644
--- a/ui/views/examples/widget_example.cc
+++ b/ui/views/examples/widget_example.cc
@@ -8,8 +8,8 @@
#include "ui/views/controls/button/text_button.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/layout_manager.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
namespace examples {
diff --git a/ui/views/focus/accelerator_handler_gtk_unittest.cc b/ui/views/focus/accelerator_handler_gtk_unittest.cc
index cdf24e1..d4db6f5 100644
--- a/ui/views/focus/accelerator_handler_gtk_unittest.cc
+++ b/ui/views/focus/accelerator_handler_gtk_unittest.cc
@@ -9,9 +9,9 @@
#include "ui/gfx/rect.h"
#include "ui/views/focus/accelerator_handler.h"
#include "ui/views/focus/focus_manager.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/focus/external_focus_tracker.cc b/ui/views/focus/external_focus_tracker.cc
index 7e58bc6..cd14496 100644
--- a/ui/views/focus/external_focus_tracker.cc
+++ b/ui/views/focus/external_focus_tracker.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "ui/views/focus/view_storage.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc
index 61567bc..ca2a55f 100644
--- a/ui/views/focus/focus_manager.cc
+++ b/ui/views/focus/focus_manager.cc
@@ -15,9 +15,9 @@
#include "ui/views/focus/focus_search.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/focus/widget_focus_manager.h"
+#include "ui/views/view.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/focus/focus_search.cc b/ui/views/focus/focus_search.cc
index e1f3c7b..56ec02f 100644
--- a/ui/views/focus/focus_search.cc
+++ b/ui/views/focus/focus_search.cc
@@ -5,7 +5,7 @@
#include "base/logging.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/focus_search.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/focus/focus_search.h b/ui/views/focus/focus_search.h
index 9fe37a0..50ba6f8 100644
--- a/ui/views/focus/focus_search.h
+++ b/ui/views/focus/focus_search.h
@@ -6,7 +6,7 @@
#define UI_VIEWS_FOCUS_FOCUS_SEARCH_H_
#pragma once
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/focus/view_storage.h b/ui/views/focus/view_storage.h
index 7d748e2..80ea032 100644
--- a/ui/views/focus/view_storage.h
+++ b/ui/views/focus/view_storage.h
@@ -7,7 +7,7 @@
#pragma once
#include "base/memory/singleton.h"
-#include "views/view.h"
+#include "ui/views/view.h"
// This class is a simple storage place for storing/retrieving views. It is
// used for example in the FocusManager to store/restore focused views when the
diff --git a/ui/views/ime/input_method_base.cc b/ui/views/ime/input_method_base.cc
index cb9573c..14d2efd 100644
--- a/ui/views/ime/input_method_base.cc
+++ b/ui/views/ime/input_method_base.cc
@@ -5,8 +5,8 @@
#include "ui/base/ime/text_input_client.h"
#include "ui/views/ime/input_method_base.h"
#include "ui/views/ime/text_input_type_tracker.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
#include "base/logging.h"
diff --git a/ui/views/ime/input_method_gtk.h b/ui/views/ime/input_method_gtk.h
index 670669f..ddb9f240 100644
--- a/ui/views/ime/input_method_gtk.h
+++ b/ui/views/ime/input_method_gtk.h
@@ -14,7 +14,7 @@
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/views/ime/input_method_base.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/ime/input_method_ibus.h b/ui/views/ime/input_method_ibus.h
index c4b516b..8af9c11 100644
--- a/ui/views/ime/input_method_ibus.h
+++ b/ui/views/ime/input_method_ibus.h
@@ -19,7 +19,7 @@
#include "ui/base/ime/text_input_client.h"
#include "ui/views/events/event.h"
#include "ui/views/ime/input_method_base.h"
-#include "views/view.h"
+#include "ui/views/view.h"
// Forward declarations, so that we don't need to include ibus.h in this file.
typedef struct _GAsyncResult GAsyncResult;
diff --git a/ui/views/ime/input_method_win.h b/ui/views/ime/input_method_win.h
index 5a34673..2be706c 100644
--- a/ui/views/ime/input_method_win.h
+++ b/ui/views/ime/input_method_win.h
@@ -14,8 +14,8 @@
#include "base/compiler_specific.h"
#include "ui/base/win/ime_input.h"
#include "ui/views/ime/input_method_base.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/ime/mock_input_method.h b/ui/views/ime/mock_input_method.h
index 5384661..1fe432e 100644
--- a/ui/views/ime/mock_input_method.h
+++ b/ui/views/ime/mock_input_method.h
@@ -12,7 +12,7 @@
#include "base/compiler_specific.h"
#include "ui/base/ime/composition_text.h"
#include "ui/views/ime/input_method_base.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/layout/box_layout.cc b/ui/views/layout/box_layout.cc
index 7471b4c..332322f 100644
--- a/ui/views/layout/box_layout.cc
+++ b/ui/views/layout/box_layout.cc
@@ -6,7 +6,7 @@
#include "ui/gfx/insets.h"
#include "ui/gfx/rect.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/layout/box_layout_unittest.cc b/ui/views/layout/box_layout_unittest.cc
index 0430c0c..dcf3227 100644
--- a/ui/views/layout/box_layout_unittest.cc
+++ b/ui/views/layout/box_layout_unittest.cc
@@ -4,7 +4,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/layout/box_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
class StaticSizedView : public views::View {
public:
diff --git a/ui/views/layout/fill_layout.h b/ui/views/layout/fill_layout.h
index b7d4c41..59a3f5d 100644
--- a/ui/views/layout/fill_layout.h
+++ b/ui/views/layout/fill_layout.h
@@ -8,7 +8,7 @@
#include "base/compiler_specific.h"
#include "ui/views/layout/layout_manager.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/layout/grid_layout.cc b/ui/views/layout/grid_layout.cc
index 7444b8b..8fb1005 100644
--- a/ui/views/layout/grid_layout.cc
+++ b/ui/views/layout/grid_layout.cc
@@ -10,7 +10,7 @@
#include "base/stl_util.h"
#include "ui/gfx/insets.h"
#include "ui/views/layout/layout_constants.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/layout/grid_layout.h b/ui/views/layout/grid_layout.h
index a57e16d..70e9502 100644
--- a/ui/views/layout/grid_layout.h
+++ b/ui/views/layout/grid_layout.h
@@ -11,7 +11,7 @@
#include "base/compiler_specific.h"
#include "ui/views/layout/layout_manager.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace gfx {
class Insets;
diff --git a/ui/views/layout/grid_layout_unittest.cc b/ui/views/layout/grid_layout_unittest.cc
index d7911c6..4c29cc6 100644
--- a/ui/views/layout/grid_layout_unittest.cc
+++ b/ui/views/layout/grid_layout_unittest.cc
@@ -4,7 +4,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/layout/grid_layout.h"
-#include "views/view.h"
+#include "ui/views/view.h"
using views::ColumnSet;
using views::GridLayout;
diff --git a/ui/views/layout/layout_manager.cc b/ui/views/layout/layout_manager.cc
index f2b4e8a..188cc6f1 100644
--- a/ui/views/layout/layout_manager.cc
+++ b/ui/views/layout/layout_manager.cc
@@ -4,7 +4,7 @@
#include "ui/views/layout/layout_manager.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/mouse_watcher.cc b/ui/views/mouse_watcher.cc
index 555af23..1115901 100644
--- a/ui/views/mouse_watcher.cc
+++ b/ui/views/mouse_watcher.cc
@@ -11,8 +11,8 @@
#include "base/message_loop.h"
#include "ui/base/events.h"
#include "ui/gfx/screen.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/touchui/gesture_manager.cc b/ui/views/touchui/gesture_manager.cc
index 8aba2a31..4dd6b0a 100644
--- a/ui/views/touchui/gesture_manager.cc
+++ b/ui/views/touchui/gesture_manager.cc
@@ -10,8 +10,8 @@
#include "base/logging.h"
#include "ui/views/events/event.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/touchui/gesture_manager.h b/ui/views/touchui/gesture_manager.h
index 50e266c..e5ec4b5 100644
--- a/ui/views/touchui/gesture_manager.h
+++ b/ui/views/touchui/gesture_manager.h
@@ -7,7 +7,7 @@
#pragma once
#include "base/memory/singleton.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace ui {
enum TouchStatus;
diff --git a/ui/views/touchui/touch_selection_controller.h b/ui/views/touchui/touch_selection_controller.h
index c117dc2..5318c9d 100644
--- a/ui/views/touchui/touch_selection_controller.h
+++ b/ui/views/touchui/touch_selection_controller.h
@@ -8,7 +8,7 @@
#include "ui/base/models/simple_menu_model.h"
#include "ui/gfx/point.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/touchui/touch_selection_controller_impl.h b/ui/views/touchui/touch_selection_controller_impl.h
index 494482e..f0d5a5d 100644
--- a/ui/views/touchui/touch_selection_controller_impl.h
+++ b/ui/views/touchui/touch_selection_controller_impl.h
@@ -9,7 +9,7 @@
#include "base/timer.h"
#include "ui/gfx/point.h"
#include "ui/views/touchui/touch_selection_controller.h"
-#include "views/view.h"
+#include "ui/views/view.h"
#include "views/views_export.h"
namespace views {
diff --git a/ui/views/view.cc b/ui/views/view.cc
new file mode 100644
index 0000000..09d3cbe
--- /dev/null
+++ b/ui/views/view.cc
@@ -0,0 +1,2061 @@
+// 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/view.h"
+
+#include <algorithm>
+
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/compositor/compositor.h"
+#include "ui/gfx/compositor/layer.h"
+#include "ui/gfx/compositor/layer_animator.h"
+#include "ui/gfx/interpolated_transform.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/point3.h"
+#include "ui/gfx/transform.h"
+#include "ui/views/context_menu_controller.h"
+#include "ui/views/drag_controller.h"
+#include "ui/views/layout/layout_manager.h"
+#include "ui/views/widget/native_widget_private.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/tooltip_manager.h"
+#include "ui/views/widget/widget.h"
+#include "views/background.h"
+#include "views/views_delegate.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_gdi_object.h"
+#include "ui/views/accessibility/native_view_accessibility_win.h"
+#endif
+#if defined(TOOLKIT_USES_GTK)
+#include "ui/base/gtk/scoped_handle_gtk.h"
+#endif
+
+namespace {
+
+// Whether to use accelerated compositing when necessary (e.g. when a view has a
+// transformation).
+#if defined(VIEWS_COMPOSITOR)
+bool use_acceleration_when_possible = true;
+#else
+bool use_acceleration_when_possible = false;
+#endif
+
+// Saves the drawing state, and restores the state when going out of scope.
+class ScopedCanvas {
+ public:
+ explicit ScopedCanvas(gfx::Canvas* canvas) : canvas_(canvas) {
+ if (canvas_)
+ canvas_->Save();
+ }
+ ~ScopedCanvas() {
+ if (canvas_)
+ canvas_->Restore();
+ }
+ void SetCanvas(gfx::Canvas* canvas) {
+ if (canvas_)
+ canvas_->Restore();
+ canvas_ = canvas;
+ canvas_->Save();
+ }
+
+ private:
+ gfx::Canvas* canvas_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCanvas);
+};
+
+// Returns the top view in |view|'s hierarchy.
+const views::View* GetHierarchyRoot(const views::View* view) {
+ const views::View* root = view;
+ while (root && root->parent())
+ root = root->parent();
+ return root;
+}
+
+} // namespace
+
+namespace views {
+
+// static
+ViewsDelegate* ViewsDelegate::views_delegate = NULL;
+
+// static
+const char View::kViewClassName[] = "views/View";
+
+////////////////////////////////////////////////////////////////////////////////
+// View, public:
+
+// TO BE MOVED -----------------------------------------------------------------
+
+void View::SetHotTracked(bool flag) {
+}
+
+bool View::IsHotTracked() const {
+ return false;
+}
+
+// Creation and lifetime -------------------------------------------------------
+
+View::View()
+ : parent_owned_(true),
+ id_(0),
+ group_(-1),
+ parent_(NULL),
+ visible_(true),
+ enabled_(true),
+ painting_enabled_(true),
+ registered_for_visible_bounds_notification_(false),
+ clip_x_(0.0),
+ clip_y_(0.0),
+ needs_layout_(true),
+ flip_canvas_on_paint_for_rtl_ui_(false),
+ paint_to_layer_(false),
+ accelerator_registration_delayed_(false),
+ accelerator_focus_manager_(NULL),
+ registered_accelerator_count_(0),
+ next_focusable_view_(NULL),
+ previous_focusable_view_(NULL),
+ focusable_(false),
+ accessibility_focusable_(false),
+ context_menu_controller_(NULL),
+ drag_controller_(NULL) {
+}
+
+View::~View() {
+ if (parent_)
+ parent_->RemoveChildView(this);
+
+ for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) {
+ (*i)->parent_ = NULL;
+ if ((*i)->parent_owned())
+ delete *i;
+ }
+
+#if defined(OS_WIN)
+ if (native_view_accessibility_win_.get())
+ native_view_accessibility_win_->set_view(NULL);
+#endif
+}
+
+// Tree operations -------------------------------------------------------------
+
+const Widget* View::GetWidget() const {
+ // The root view holds a reference to this view hierarchy's Widget.
+ return parent_ ? parent_->GetWidget() : NULL;
+}
+
+Widget* View::GetWidget() {
+ return const_cast<Widget*>(const_cast<const View*>(this)->GetWidget());
+}
+
+void View::AddChildView(View* view) {
+ AddChildViewAt(view, child_count());
+}
+
+void View::AddChildViewAt(View* view, int index) {
+ CHECK_NE(view, this) << "You cannot add a view as its own child";
+
+ // If |view| has a parent, remove it from its parent.
+ View* parent = view->parent_;
+ if (parent)
+ parent->RemoveChildView(view);
+
+ // Sets the prev/next focus views.
+ InitFocusSiblings(view, index);
+
+ // Let's insert the view.
+ view->parent_ = this;
+ children_.insert(children_.begin() + index, view);
+
+ for (View* v = this; v; v = v->parent_)
+ v->ViewHierarchyChangedImpl(false, true, this, view);
+
+ view->PropagateAddNotifications(this, view);
+ UpdateTooltip();
+ if (GetWidget())
+ RegisterChildrenForVisibleBoundsNotification(view);
+
+ if (layout_manager_.get())
+ layout_manager_->ViewAdded(this, view);
+
+ if (use_acceleration_when_possible)
+ ReorderLayers();
+
+ // Make sure the visibility of the child layers are correct.
+ // If any of the parent View is hidden, then the layers of the subtree
+ // rooted at |this| should be hidden. Otherwise, all the child layers should
+ // inherit the visibility of the owner View.
+ UpdateLayerVisibility();
+}
+
+void View::ReorderChildView(View* view, int index) {
+ DCHECK_EQ(view->parent_, this);
+ if (index < 0)
+ index = child_count() - 1;
+ else if (index >= child_count())
+ return;
+ if (children_[index] == view)
+ return;
+
+ const Views::iterator i(std::find(children_.begin(), children_.end(), view));
+ DCHECK(i != children_.end());
+ children_.erase(i);
+
+ // Unlink the view first
+ View* next_focusable = view->next_focusable_view_;
+ View* prev_focusable = view->previous_focusable_view_;
+ if (prev_focusable)
+ prev_focusable->next_focusable_view_ = next_focusable;
+ if (next_focusable)
+ next_focusable->previous_focusable_view_ = prev_focusable;
+
+ // Add it in the specified index now.
+ InitFocusSiblings(view, index);
+ children_.insert(children_.begin() + index, view);
+
+ if (use_acceleration_when_possible)
+ ReorderLayers();
+}
+
+void View::RemoveChildView(View* view) {
+ DoRemoveChildView(view, true, true, false);
+}
+
+void View::RemoveAllChildViews(bool delete_children) {
+ while (!children_.empty())
+ DoRemoveChildView(children_.front(), false, false, delete_children);
+ UpdateTooltip();
+}
+
+bool View::Contains(const View* view) const {
+ for (const View* v = view; v; v = v->parent_) {
+ if (v == this)
+ return true;
+ }
+ return false;
+}
+
+int View::GetIndexOf(const View* view) const {
+ Views::const_iterator i(std::find(children_.begin(), children_.end(), view));
+ return i != children_.end() ? static_cast<int>(i - children_.begin()) : -1;
+}
+
+// Size and disposition --------------------------------------------------------
+
+void View::SetBounds(int x, int y, int width, int height) {
+ SetBoundsRect(gfx::Rect(x, y, std::max(0, width), std::max(0, height)));
+}
+
+void View::SetBoundsRect(const gfx::Rect& bounds) {
+ if (bounds == bounds_) {
+ if (needs_layout_) {
+ needs_layout_ = false;
+ Layout();
+ SchedulePaint();
+ }
+ return;
+ }
+
+ if (IsVisible()) {
+ // Paint where the view is currently.
+ SchedulePaintBoundsChanged(
+ bounds_.size() == bounds.size() ? SCHEDULE_PAINT_SIZE_SAME :
+ SCHEDULE_PAINT_SIZE_CHANGED);
+ }
+
+ gfx::Rect prev = bounds_;
+ bounds_ = bounds;
+ BoundsChanged(prev);
+}
+
+void View::SetSize(const gfx::Size& size) {
+ SetBounds(x(), y(), size.width(), size.height());
+}
+
+void View::SetPosition(const gfx::Point& position) {
+ SetBounds(position.x(), position.y(), width(), height());
+}
+
+void View::SetX(int x) {
+ SetBounds(x, y(), width(), height());
+}
+
+void View::SetY(int y) {
+ SetBounds(x(), y, width(), height());
+}
+
+gfx::Rect View::GetContentsBounds() const {
+ gfx::Rect contents_bounds(GetLocalBounds());
+ if (border_.get()) {
+ gfx::Insets insets;
+ border_->GetInsets(&insets);
+ contents_bounds.Inset(insets);
+ }
+ return contents_bounds;
+}
+
+gfx::Rect View::GetLocalBounds() const {
+ return gfx::Rect(gfx::Point(), size());
+}
+
+gfx::Insets View::GetInsets() const {
+ gfx::Insets insets;
+ if (border_.get())
+ border_->GetInsets(&insets);
+ return insets;
+}
+
+gfx::Rect View::GetVisibleBounds() const {
+ if (!IsVisibleInRootView())
+ return gfx::Rect();
+ gfx::Rect vis_bounds(0, 0, width(), height());
+ gfx::Rect ancestor_bounds;
+ const View* view = this;
+ ui::Transform transform;
+
+ while (view != NULL && !vis_bounds.IsEmpty()) {
+ transform.ConcatTransform(view->GetTransform());
+ transform.ConcatTranslate(static_cast<float>(view->GetMirroredX()),
+ static_cast<float>(view->y()));
+
+ vis_bounds = view->ConvertRectToParent(vis_bounds);
+ const View* ancestor = view->parent_;
+ if (ancestor != NULL) {
+ ancestor_bounds.SetRect(0, 0, ancestor->width(), ancestor->height());
+ vis_bounds = vis_bounds.Intersect(ancestor_bounds);
+ } else if (!view->GetWidget()) {
+ // If the view has no Widget, we're not visible. Return an empty rect.
+ return gfx::Rect();
+ }
+ view = ancestor;
+ }
+ if (vis_bounds.IsEmpty())
+ return vis_bounds;
+ // Convert back to this views coordinate system.
+ transform.TransformRectReverse(&vis_bounds);
+ return vis_bounds;
+}
+
+gfx::Rect View::GetScreenBounds() const {
+ gfx::Point origin;
+ View::ConvertPointToScreen(this, &origin);
+ return gfx::Rect(origin, size());
+}
+
+gfx::Size View::GetPreferredSize() {
+ if (layout_manager_.get())
+ return layout_manager_->GetPreferredSize(this);
+ return gfx::Size();
+}
+
+int View::GetBaseline() const {
+ return -1;
+}
+
+void View::SizeToPreferredSize() {
+ gfx::Size prefsize = GetPreferredSize();
+ if ((prefsize.width() != width()) || (prefsize.height() != height()))
+ SetBounds(x(), y(), prefsize.width(), prefsize.height());
+}
+
+gfx::Size View::GetMinimumSize() {
+ return GetPreferredSize();
+}
+
+int View::GetHeightForWidth(int w) {
+ if (layout_manager_.get())
+ return layout_manager_->GetPreferredHeightForWidth(this, w);
+ return GetPreferredSize().height();
+}
+
+void View::SetVisible(bool visible) {
+ if (visible != visible_) {
+ // If the View is currently visible, schedule paint to refresh parent.
+ // TODO(beng): not sure we should be doing this if we have a layer.
+ if (visible_)
+ SchedulePaint();
+
+ visible_ = visible;
+
+ // This notifies all sub-views recursively.
+ PropagateVisibilityNotifications(this, visible_);
+ UpdateLayerVisibility();
+
+ // If we are newly visible, schedule paint.
+ if (visible_)
+ SchedulePaint();
+ }
+}
+
+bool View::IsVisible() const {
+ return visible_;
+}
+
+bool View::IsVisibleInRootView() const {
+ return IsVisible() && parent_ ? parent_->IsVisibleInRootView() : false;
+}
+
+void View::SetEnabled(bool enabled) {
+ if (enabled != enabled_) {
+ enabled_ = enabled;
+ OnEnabledChanged();
+ }
+}
+
+bool View::IsEnabled() const {
+ return enabled_;
+}
+
+void View::OnEnabledChanged() {
+ SchedulePaint();
+}
+
+// Transformations -------------------------------------------------------------
+
+const ui::Transform& View::GetTransform() const {
+ static const ui::Transform* no_op = new ui::Transform;
+ return layer() ? layer()->transform() : *no_op;
+}
+
+void View::SetTransform(const ui::Transform& transform) {
+ if (!transform.HasChange()) {
+ if (layer()) {
+ layer()->SetTransform(transform);
+ if (!paint_to_layer_)
+ DestroyLayer();
+ } else {
+ // Nothing.
+ }
+ } else {
+ if (!layer())
+ CreateLayer();
+ layer()->SetTransform(transform);
+ layer()->ScheduleDraw();
+ }
+}
+
+void View::SetPaintToLayer(bool paint_to_layer) {
+ paint_to_layer_ = paint_to_layer;
+ if (paint_to_layer_ && !layer()) {
+ CreateLayer();
+ } else if (!paint_to_layer_ && layer()) {
+ DestroyLayer();
+ }
+}
+
+// RTL positioning -------------------------------------------------------------
+
+gfx::Rect View::GetMirroredBounds() const {
+ gfx::Rect bounds(bounds_);
+ bounds.set_x(GetMirroredX());
+ return bounds;
+}
+
+gfx::Point View::GetMirroredPosition() const {
+ return gfx::Point(GetMirroredX(), y());
+}
+
+int View::GetMirroredX() const {
+ return parent_ ? parent_->GetMirroredXForRect(bounds_) : x();
+}
+
+int View::GetMirroredXForRect(const gfx::Rect& bounds) const {
+ return base::i18n::IsRTL() ?
+ (width() - bounds.x() - bounds.width()) : bounds.x();
+}
+
+int View::GetMirroredXInView(int x) const {
+ return base::i18n::IsRTL() ? width() - x : x;
+}
+
+int View::GetMirroredXWithWidthInView(int x, int w) const {
+ return base::i18n::IsRTL() ? width() - x - w : x;
+}
+
+// Layout ----------------------------------------------------------------------
+
+void View::Layout() {
+ needs_layout_ = false;
+
+ // If we have a layout manager, let it handle the layout for us.
+ if (layout_manager_.get())
+ layout_manager_->Layout(this);
+
+ // Make sure to propagate the Layout() call to any children that haven't
+ // received it yet through the layout manager and need to be laid out. This
+ // is needed for the case when the child requires a layout but its bounds
+ // weren't changed by the layout manager. If there is no layout manager, we
+ // just propagate the Layout() call down the hierarchy, so whoever receives
+ // the call can take appropriate action.
+ for (int i = 0, count = child_count(); i < count; ++i) {
+ View* child = child_at(i);
+ if (child->needs_layout_ || !layout_manager_.get()) {
+ child->needs_layout_ = false;
+ child->Layout();
+ }
+ }
+}
+
+void View::InvalidateLayout() {
+ // Always invalidate up. This is needed to handle the case of us already being
+ // valid, but not our parent.
+ needs_layout_ = true;
+ if (parent_)
+ parent_->InvalidateLayout();
+}
+
+LayoutManager* View::GetLayoutManager() const {
+ return layout_manager_.get();
+}
+
+void View::SetLayoutManager(LayoutManager* layout_manager) {
+ if (layout_manager_.get())
+ layout_manager_->Uninstalled(this);
+
+ layout_manager_.reset(layout_manager);
+ if (layout_manager_.get())
+ layout_manager_->Installed(this);
+}
+
+// Attributes ------------------------------------------------------------------
+
+std::string View::GetClassName() const {
+ return kViewClassName;
+}
+
+View* View::GetAncestorWithClassName(const std::string& name) {
+ for (View* view = this; view; view = view->parent_) {
+ if (view->GetClassName() == name)
+ return view;
+ }
+ return NULL;
+}
+
+const View* View::GetViewByID(int id) const {
+ if (id == id_)
+ return const_cast<View*>(this);
+
+ for (int i = 0, count = child_count(); i < count; ++i) {
+ const View* view = child_at(i)->GetViewByID(id);
+ if (view)
+ return view;
+ }
+ return NULL;
+}
+
+View* View::GetViewByID(int id) {
+ return const_cast<View*>(const_cast<const View*>(this)->GetViewByID(id));
+}
+
+void View::SetGroup(int gid) {
+ // Don't change the group id once it's set.
+ DCHECK(group_ == -1 || group_ == gid);
+ group_ = gid;
+}
+
+int View::GetGroup() const {
+ return group_;
+}
+
+bool View::IsGroupFocusTraversable() const {
+ return true;
+}
+
+void View::GetViewsInGroup(int group, Views* views) {
+ if (group_ == group)
+ views->push_back(this);
+
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->GetViewsInGroup(group, views);
+}
+
+View* View::GetSelectedViewForGroup(int group) {
+ Views views;
+ GetWidget()->GetRootView()->GetViewsInGroup(group, &views);
+ return views.empty() ? NULL : views[0];
+}
+
+// Coordinate conversion -------------------------------------------------------
+
+// static
+void View::ConvertPointToView(const View* source,
+ const View* target,
+ gfx::Point* point) {
+ if (source == target)
+ return;
+
+ // |source| can be NULL.
+ const View* root = GetHierarchyRoot(target);
+ if (source) {
+ CHECK_EQ(GetHierarchyRoot(source), root);
+
+ if (source != root)
+ source->ConvertPointForAncestor(root, point);
+ }
+
+ if (target != root)
+ target->ConvertPointFromAncestor(root, point);
+
+ // API defines NULL |source| as returning the point in screen coordinates.
+ if (!source) {
+ *point = point->Subtract(
+ root->GetWidget()->GetClientAreaScreenBounds().origin());
+ }
+}
+
+// static
+void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
+ DCHECK(src);
+ DCHECK(p);
+
+ src->ConvertPointForAncestor(NULL, p);
+}
+
+// static
+void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
+ DCHECK(dest);
+ DCHECK(p);
+
+ dest->ConvertPointFromAncestor(NULL, p);
+}
+
+// static
+void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
+ DCHECK(src);
+ DCHECK(p);
+
+ // If the view is not connected to a tree, there's nothing we can do.
+ const Widget* widget = src->GetWidget();
+ if (widget) {
+ ConvertPointToWidget(src, p);
+ gfx::Rect r = widget->GetClientAreaScreenBounds();
+ p->SetPoint(p->x() + r.x(), p->y() + r.y());
+ }
+}
+
+gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const {
+ gfx::Rect x_rect = rect;
+ GetTransform().TransformRect(&x_rect);
+ x_rect.Offset(GetMirroredPosition());
+ return x_rect;
+}
+
+gfx::Rect View::ConvertRectToWidget(const gfx::Rect& rect) const {
+ gfx::Rect x_rect = rect;
+ for (const View* v = this; v; v = v->parent_)
+ x_rect = v->ConvertRectToParent(x_rect);
+ return x_rect;
+}
+
+// Painting --------------------------------------------------------------------
+
+void View::SchedulePaint() {
+ SchedulePaintInRect(GetLocalBounds());
+}
+
+void View::SchedulePaintInRect(const gfx::Rect& rect) {
+ if (!IsVisible() || !painting_enabled_)
+ return;
+
+ if (layer()) {
+ layer()->SchedulePaint(rect);
+ } else if (parent_) {
+ // Translate the requested paint rect to the parent's coordinate system
+ // then pass this notification up to the parent.
+ parent_->SchedulePaintInRect(ConvertRectToParent(rect));
+ }
+}
+
+void View::Paint(gfx::Canvas* canvas) {
+ TRACE_EVENT0("views", "View::Paint");
+
+ ScopedCanvas scoped_canvas(canvas);
+
+ // Paint this View and its children, setting the clip rect to the bounds
+ // of this View and translating the origin to the local bounds' top left
+ // point.
+ //
+ // Note that the X (or left) position we pass to ClipRectInt takes into
+ // consideration whether or not the view uses a right-to-left layout so that
+ // we paint our view in its mirrored position if need be.
+ if (!canvas->ClipRect(gfx::Rect(GetMirroredX(), y(),
+ width() - static_cast<int>(clip_x_),
+ height() - static_cast<int>(clip_y_)))) {
+ return;
+ }
+ // Non-empty clip, translate the graphics such that 0,0 corresponds to
+ // where this view is located (related to its parent).
+ canvas->Translate(GetMirroredPosition());
+ canvas->Transform(GetTransform());
+
+ PaintCommon(canvas);
+}
+
+ThemeProvider* View::GetThemeProvider() const {
+ const Widget* widget = GetWidget();
+ return widget ? widget->GetThemeProvider() : NULL;
+}
+
+// Accelerated Painting --------------------------------------------------------
+
+// static
+void View::set_use_acceleration_when_possible(bool use) {
+ use_acceleration_when_possible = use;
+}
+
+// static
+bool View::get_use_acceleration_when_possible() {
+ return use_acceleration_when_possible;
+}
+
+// Input -----------------------------------------------------------------------
+
+View* View::GetEventHandlerForPoint(const gfx::Point& point) {
+ // Walk the child Views recursively looking for the View that most
+ // tightly encloses the specified point.
+ for (int i = child_count() - 1; i >= 0; --i) {
+ View* child = child_at(i);
+ if (!child->IsVisible())
+ continue;
+
+ gfx::Point point_in_child_coords(point);
+ View::ConvertPointToView(this, child, &point_in_child_coords);
+ if (child->HitTest(point_in_child_coords))
+ return child->GetEventHandlerForPoint(point_in_child_coords);
+ }
+ return this;
+}
+
+gfx::NativeCursor View::GetCursor(const MouseEvent& event) {
+#if defined(OS_WIN) && !defined(USE_AURA)
+ static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
+ return arrow;
+#else
+ return gfx::kNullCursor;
+#endif
+}
+
+bool View::HitTest(const gfx::Point& l) const {
+ if (GetLocalBounds().Contains(l)) {
+ if (HasHitTestMask()) {
+ gfx::Path mask;
+ GetHitTestMask(&mask);
+#if defined(USE_AURA)
+ // TODO: should we use this every where?
+ SkRegion clip_region;
+ clip_region.setRect(0, 0, width(), height());
+ SkRegion mask_region;
+ return mask_region.setPath(mask, clip_region) &&
+ mask_region.contains(l.x(), l.y());
+#elif defined(OS_WIN)
+ base::win::ScopedRegion rgn(mask.CreateNativeRegion());
+ return !!PtInRegion(rgn, l.x(), l.y());
+#elif defined(TOOLKIT_USES_GTK)
+ ui::ScopedRegion rgn(mask.CreateNativeRegion());
+ return gdk_region_point_in(rgn.Get(), l.x(), l.y());
+#endif
+ }
+ // No mask, but inside our bounds.
+ return true;
+ }
+ // Outside our bounds.
+ return false;
+}
+
+bool View::OnMousePressed(const MouseEvent& event) {
+ return false;
+}
+
+bool View::OnMouseDragged(const MouseEvent& event) {
+ return false;
+}
+
+void View::OnMouseReleased(const MouseEvent& event) {
+}
+
+void View::OnMouseCaptureLost() {
+}
+
+void View::OnMouseMoved(const MouseEvent& event) {
+}
+
+void View::OnMouseEntered(const MouseEvent& event) {
+}
+
+void View::OnMouseExited(const MouseEvent& event) {
+}
+
+ui::TouchStatus View::OnTouchEvent(const TouchEvent& event) {
+ DVLOG(1) << "visited the OnTouchEvent";
+ return ui::TOUCH_STATUS_UNKNOWN;
+}
+
+void View::SetMouseHandler(View *new_mouse_handler) {
+ // It is valid for new_mouse_handler to be NULL
+ if (parent_)
+ parent_->SetMouseHandler(new_mouse_handler);
+}
+
+bool View::OnKeyPressed(const KeyEvent& event) {
+ return false;
+}
+
+bool View::OnKeyReleased(const KeyEvent& event) {
+ return false;
+}
+
+bool View::OnMouseWheel(const MouseWheelEvent& event) {
+ return false;
+}
+
+ui::TextInputClient* View::GetTextInputClient() {
+ return NULL;
+}
+
+InputMethod* View::GetInputMethod() {
+ Widget* widget = GetWidget();
+ return widget ? widget->GetInputMethod() : NULL;
+}
+
+// Accelerators ----------------------------------------------------------------
+
+void View::AddAccelerator(const ui::Accelerator& accelerator) {
+ if (!accelerators_.get())
+ accelerators_.reset(new std::vector<ui::Accelerator>());
+
+ DCHECK(std::find(accelerators_->begin(), accelerators_->end(), accelerator) ==
+ accelerators_->end())
+ << "Registering the same accelerator multiple times";
+
+ accelerators_->push_back(accelerator);
+ RegisterPendingAccelerators();
+}
+
+void View::RemoveAccelerator(const ui::Accelerator& accelerator) {
+ if (!accelerators_.get()) {
+ NOTREACHED() << "Removing non-existing accelerator";
+ return;
+ }
+
+ std::vector<ui::Accelerator>::iterator i(
+ std::find(accelerators_->begin(), accelerators_->end(), accelerator));
+ if (i == accelerators_->end()) {
+ NOTREACHED() << "Removing non-existing accelerator";
+ return;
+ }
+
+ size_t index = i - accelerators_->begin();
+ accelerators_->erase(i);
+ if (index >= registered_accelerator_count_) {
+ // The accelerator is not registered to FocusManager.
+ return;
+ }
+ --registered_accelerator_count_;
+
+ // Providing we are attached to a Widget and registered with a focus manager,
+ // we should de-register from that focus manager now.
+ if (GetWidget() && accelerator_focus_manager_)
+ accelerator_focus_manager_->UnregisterAccelerator(accelerator, this);
+}
+
+void View::ResetAccelerators() {
+ if (accelerators_.get())
+ UnregisterAccelerators(false);
+}
+
+bool View::AcceleratorPressed(const ui::Accelerator& accelerator) {
+ return false;
+}
+
+// Focus -----------------------------------------------------------------------
+
+bool View::HasFocus() const {
+ const FocusManager* focus_manager = GetFocusManager();
+ return focus_manager && (focus_manager->GetFocusedView() == this);
+}
+
+View* View::GetNextFocusableView() {
+ return next_focusable_view_;
+}
+
+const View* View::GetNextFocusableView() const {
+ return next_focusable_view_;
+}
+
+View* View::GetPreviousFocusableView() {
+ return previous_focusable_view_;
+}
+
+void View::SetNextFocusableView(View* view) {
+ view->previous_focusable_view_ = this;
+ next_focusable_view_ = view;
+}
+
+bool View::IsFocusableInRootView() const {
+ return IsFocusable() && IsVisibleInRootView();
+}
+
+bool View::IsAccessibilityFocusableInRootView() const {
+ return (focusable_ || accessibility_focusable_) && IsEnabled() &&
+ IsVisibleInRootView();
+}
+
+FocusManager* View::GetFocusManager() {
+ Widget* widget = GetWidget();
+ return widget ? widget->GetFocusManager() : NULL;
+}
+
+const FocusManager* View::GetFocusManager() const {
+ const Widget* widget = GetWidget();
+ return widget ? widget->GetFocusManager() : NULL;
+}
+
+void View::RequestFocus() {
+ FocusManager* focus_manager = GetFocusManager();
+ if (focus_manager && IsFocusableInRootView())
+ focus_manager->SetFocusedView(this);
+}
+
+bool View::SkipDefaultKeyEventProcessing(const KeyEvent& event) {
+ return false;
+}
+
+FocusTraversable* View::GetFocusTraversable() {
+ return NULL;
+}
+
+FocusTraversable* View::GetPaneFocusTraversable() {
+ return NULL;
+}
+
+// Tooltips --------------------------------------------------------------------
+
+bool View::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+ return false;
+}
+
+bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) const {
+ return false;
+}
+
+// Context menus ---------------------------------------------------------------
+
+void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) {
+ if (!context_menu_controller_)
+ return;
+
+ context_menu_controller_->ShowContextMenuForView(this, p, is_mouse_gesture);
+}
+
+// Drag and drop ---------------------------------------------------------------
+
+bool View::GetDropFormats(
+ int* formats,
+ std::set<OSExchangeData::CustomFormat>* custom_formats) {
+ return false;
+}
+
+bool View::AreDropTypesRequired() {
+ return false;
+}
+
+bool View::CanDrop(const OSExchangeData& data) {
+ // TODO(sky): when I finish up migration, this should default to true.
+ return false;
+}
+
+void View::OnDragEntered(const DropTargetEvent& event) {
+}
+
+int View::OnDragUpdated(const DropTargetEvent& event) {
+ return ui::DragDropTypes::DRAG_NONE;
+}
+
+void View::OnDragExited() {
+}
+
+int View::OnPerformDrop(const DropTargetEvent& event) {
+ return ui::DragDropTypes::DRAG_NONE;
+}
+
+void View::OnDragDone() {
+}
+
+// static
+bool View::ExceededDragThreshold(int delta_x, int delta_y) {
+ return (abs(delta_x) > GetHorizontalDragThreshold() ||
+ abs(delta_y) > GetVerticalDragThreshold());
+}
+
+// Scrolling -------------------------------------------------------------------
+
+void View::ScrollRectToVisible(const gfx::Rect& rect) {
+ // We must take RTL UI mirroring into account when adjusting the position of
+ // the region.
+ if (parent_) {
+ gfx::Rect scroll_rect(rect);
+ scroll_rect.Offset(GetMirroredX(), y());
+ parent_->ScrollRectToVisible(scroll_rect);
+ }
+}
+
+int View::GetPageScrollIncrement(ScrollView* scroll_view,
+ bool is_horizontal, bool is_positive) {
+ return 0;
+}
+
+int View::GetLineScrollIncrement(ScrollView* scroll_view,
+ bool is_horizontal, bool is_positive) {
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// View, protected:
+
+// Size and disposition --------------------------------------------------------
+
+void View::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+}
+
+void View::PreferredSizeChanged() {
+ InvalidateLayout();
+ if (parent_)
+ parent_->ChildPreferredSizeChanged(this);
+}
+
+bool View::NeedsNotificationWhenVisibleBoundsChange() const {
+ return false;
+}
+
+void View::OnVisibleBoundsChanged() {
+}
+
+// Tree operations -------------------------------------------------------------
+
+void View::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+}
+
+void View::VisibilityChanged(View* starting_from, bool is_visible) {
+}
+
+void View::NativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ internal::RootView* root_view) {
+ FocusManager* focus_manager = GetFocusManager();
+ if (!accelerator_registration_delayed_ &&
+ accelerator_focus_manager_ &&
+ accelerator_focus_manager_ != focus_manager) {
+ UnregisterAccelerators(true);
+ accelerator_registration_delayed_ = true;
+ }
+ if (accelerator_registration_delayed_ && attached) {
+ if (focus_manager) {
+ RegisterPendingAccelerators();
+ accelerator_registration_delayed_ = false;
+ }
+ }
+}
+
+// Painting --------------------------------------------------------------------
+
+void View::PaintChildren(gfx::Canvas* canvas) {
+ TRACE_EVENT0("views", "View::PaintChildren");
+ for (int i = 0, count = child_count(); i < count; ++i)
+ if (!child_at(i)->layer())
+ child_at(i)->Paint(canvas);
+}
+
+void View::OnPaint(gfx::Canvas* canvas) {
+ TRACE_EVENT0("views", "View::OnPaint");
+ OnPaintBackground(canvas);
+ OnPaintFocusBorder(canvas);
+ OnPaintBorder(canvas);
+}
+
+void View::OnPaintBackground(gfx::Canvas* canvas) {
+ if (background_.get()) {
+ TRACE_EVENT2("views", "View::OnPaintBackground",
+ "width", canvas->GetSkCanvas()->getDevice()->width(),
+ "height", canvas->GetSkCanvas()->getDevice()->height());
+ background_->Paint(canvas, this);
+ }
+}
+
+void View::OnPaintBorder(gfx::Canvas* canvas) {
+ if (border_.get()) {
+ TRACE_EVENT2("views", "View::OnPaintBorder",
+ "width", canvas->GetSkCanvas()->getDevice()->width(),
+ "height", canvas->GetSkCanvas()->getDevice()->height());
+ border_->Paint(*this, canvas);
+ }
+}
+
+void View::OnPaintFocusBorder(gfx::Canvas* canvas) {
+ if ((IsFocusable() || IsAccessibilityFocusableInRootView()) && HasFocus()) {
+ TRACE_EVENT2("views", "views::OnPaintFocusBorder",
+ "width", canvas->GetSkCanvas()->getDevice()->width(),
+ "height", canvas->GetSkCanvas()->getDevice()->height());
+ canvas->DrawFocusRect(GetLocalBounds());
+ }
+}
+
+// Accelerated Painting --------------------------------------------------------
+
+void View::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) {
+ // This method should not have the side-effect of creating the layer.
+ if (layer())
+ layer()->SetFillsBoundsOpaquely(fills_bounds_opaquely);
+}
+
+bool View::SetExternalTexture(ui::Texture* texture) {
+ DCHECK(texture);
+ SetPaintToLayer(true);
+
+ layer()->SetExternalTexture(texture);
+
+ // Child views must not paint into the external texture. So make sure each
+ // child view has its own layer to paint into.
+ for (Views::iterator i = children_.begin(); i != children_.end(); ++i)
+ (*i)->SetPaintToLayer(true);
+
+ SchedulePaintInRect(GetLocalBounds());
+ return true;
+}
+
+void View::CalculateOffsetToAncestorWithLayer(gfx::Point* offset,
+ ui::Layer** layer_parent) {
+ if (layer()) {
+ if (layer_parent)
+ *layer_parent = layer();
+ return;
+ }
+ if (!parent_)
+ return;
+
+ offset->Offset(x(), y());
+ parent_->CalculateOffsetToAncestorWithLayer(offset, layer_parent);
+}
+
+void View::MoveLayerToParent(ui::Layer* parent_layer,
+ const gfx::Point& point) {
+ gfx::Point local_point(point);
+ if (parent_layer != layer())
+ local_point.Offset(x(), y());
+ if (layer() && parent_layer != layer()) {
+ parent_layer->Add(layer());
+ layer()->SetBounds(gfx::Rect(local_point.x(), local_point.y(),
+ width(), height()));
+ } else {
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->MoveLayerToParent(parent_layer, local_point);
+ }
+}
+
+void View::UpdateLayerVisibility() {
+ if (!use_acceleration_when_possible)
+ return;
+ bool visible = IsVisible();
+ for (const View* v = parent_; visible && v && !v->layer(); v = v->parent_)
+ visible = v->IsVisible();
+
+ UpdateChildLayerVisibility(visible);
+}
+
+void View::UpdateChildLayerVisibility(bool ancestor_visible) {
+ if (layer()) {
+ layer()->SetVisible(ancestor_visible && IsVisible());
+ } else {
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->UpdateChildLayerVisibility(ancestor_visible && IsVisible());
+ }
+}
+
+void View::UpdateChildLayerBounds(const gfx::Point& offset) {
+ if (layer()) {
+ layer()->SetBounds(gfx::Rect(offset.x(), offset.y(), width(), height()));
+ } else {
+ for (int i = 0, count = child_count(); i < count; ++i) {
+ gfx::Point new_offset(offset.x() + child_at(i)->x(),
+ offset.y() + child_at(i)->y());
+ child_at(i)->UpdateChildLayerBounds(new_offset);
+ }
+ }
+}
+
+void View::OnPaintLayer(gfx::Canvas* canvas) {
+ if (!layer() || !layer()->fills_bounds_opaquely())
+ canvas->GetSkCanvas()->drawColor(SK_ColorBLACK, SkXfermode::kClear_Mode);
+ PaintCommon(canvas);
+}
+
+void View::ReorderLayers() {
+ View* v = this;
+ while (v && !v->layer())
+ v = v->parent();
+
+ // Forward to widget in case we're in a NativeWidgetView.
+ if (!v) {
+ if (GetWidget())
+ GetWidget()->ReorderLayers();
+ } else {
+ for (Views::const_iterator i(v->children_.begin());
+ i != v->children_.end();
+ ++i)
+ (*i)->ReorderChildLayers(v->layer());
+ }
+}
+
+void View::ReorderChildLayers(ui::Layer* parent_layer) {
+ if (layer()) {
+ DCHECK_EQ(parent_layer, layer()->parent());
+ parent_layer->StackAtTop(layer());
+ } else {
+ for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i)
+ (*i)->ReorderChildLayers(parent_layer);
+ }
+}
+
+// Input -----------------------------------------------------------------------
+
+bool View::HasHitTestMask() const {
+ return false;
+}
+
+void View::GetHitTestMask(gfx::Path* mask) const {
+ DCHECK(mask);
+}
+
+// Focus -----------------------------------------------------------------------
+
+bool View::IsFocusable() const {
+ return focusable_ && IsEnabled() && IsVisible();
+}
+
+void View::OnFocus() {
+ // TODO(beng): Investigate whether it's possible for us to move this to
+ // Focus().
+ // By default, we clear the native focus. This ensures that no visible native
+ // view as the focus and that we still receive keyboard inputs.
+ FocusManager* focus_manager = GetFocusManager();
+ if (focus_manager)
+ focus_manager->ClearNativeFocus();
+
+ // TODO(beng): Investigate whether it's possible for us to move this to
+ // Focus().
+ // Notify assistive technologies of the focus change.
+ GetWidget()->NotifyAccessibilityEvent(
+ this, ui::AccessibilityTypes::EVENT_FOCUS, true);
+}
+
+void View::OnBlur() {
+}
+
+void View::Focus() {
+ SchedulePaint();
+ OnFocus();
+}
+
+void View::Blur() {
+ SchedulePaint();
+ OnBlur();
+}
+
+// Tooltips --------------------------------------------------------------------
+
+void View::TooltipTextChanged() {
+ Widget* widget = GetWidget();
+ // TooltipManager may be null if there is a problem creating it.
+ if (widget && widget->native_widget_private()->GetTooltipManager()) {
+ widget->native_widget_private()->GetTooltipManager()->
+ TooltipTextChanged(this);
+ }
+}
+
+// Context menus ---------------------------------------------------------------
+
+gfx::Point View::GetKeyboardContextMenuLocation() {
+ gfx::Rect vis_bounds = GetVisibleBounds();
+ gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2,
+ vis_bounds.y() + vis_bounds.height() / 2);
+ ConvertPointToScreen(this, &screen_point);
+ return screen_point;
+}
+
+// Drag and drop ---------------------------------------------------------------
+
+int View::GetDragOperations(const gfx::Point& press_pt) {
+ return drag_controller_ ?
+ drag_controller_->GetDragOperationsForView(this, press_pt) :
+ ui::DragDropTypes::DRAG_NONE;
+}
+
+void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) {
+ DCHECK(drag_controller_);
+ drag_controller_->WriteDragDataForView(this, press_pt, data);
+}
+
+bool View::InDrag() {
+ Widget* widget = GetWidget();
+ return widget ? widget->dragged_view() == this : false;
+}
+
+// Debugging -------------------------------------------------------------------
+
+#if !defined(NDEBUG)
+
+std::string View::PrintViewGraph(bool first) {
+ return DoPrintViewGraph(first, this);
+}
+
+std::string View::DoPrintViewGraph(bool first, View* view_with_children) {
+ // 64-bit pointer = 16 bytes of hex + "0x" + '\0' = 19.
+ const size_t kMaxPointerStringLength = 19;
+
+ std::string result;
+
+ if (first)
+ result.append("digraph {\n");
+
+ // Node characteristics.
+ char p[kMaxPointerStringLength];
+
+ size_t baseNameIndex = GetClassName().find_last_of('/');
+ if (baseNameIndex == std::string::npos)
+ baseNameIndex = 0;
+ else
+ baseNameIndex++;
+
+ char bounds_buffer[512];
+
+ // Information about current node.
+ base::snprintf(p, arraysize(bounds_buffer), "%p", view_with_children);
+ result.append(" N");
+ result.append(p+2);
+ result.append(" [label=\"");
+
+ result.append(GetClassName().substr(baseNameIndex).c_str());
+
+ base::snprintf(bounds_buffer,
+ arraysize(bounds_buffer),
+ "\\n bounds: (%d, %d), (%dx%d)",
+ this->bounds().x(),
+ this->bounds().y(),
+ this->bounds().width(),
+ this->bounds().height());
+ result.append(bounds_buffer);
+
+ if (layer() && !layer()->hole_rect().IsEmpty()) {
+ base::snprintf(bounds_buffer,
+ arraysize(bounds_buffer),
+ "\\n hole bounds: (%d, %d), (%dx%d)",
+ layer()->hole_rect().x(),
+ layer()->hole_rect().y(),
+ layer()->hole_rect().width(),
+ layer()->hole_rect().height());
+ result.append(bounds_buffer);
+ }
+
+ if (GetTransform().HasChange()) {
+ gfx::Point translation;
+ float rotation;
+ gfx::Point3f scale;
+ if (ui::InterpolatedTransform::FactorTRS(GetTransform(),
+ &translation,
+ &rotation,
+ &scale)) {
+ if (translation != gfx::Point(0, 0)) {
+ base::snprintf(bounds_buffer,
+ arraysize(bounds_buffer),
+ "\\n translation: (%d, %d)",
+ translation.x(),
+ translation.y());
+ result.append(bounds_buffer);
+ }
+
+ if (fabs(rotation) > 1e-5) {
+ base::snprintf(bounds_buffer,
+ arraysize(bounds_buffer),
+ "\\n rotation: %3.2f", rotation);
+ result.append(bounds_buffer);
+ }
+
+ if (scale.AsPoint() != gfx::Point(0, 0)) {
+ base::snprintf(bounds_buffer,
+ arraysize(bounds_buffer),
+ "\\n scale: (%2.4f, %2.4f)",
+ scale.x(),
+ scale.y());
+ result.append(bounds_buffer);
+ }
+ }
+ }
+
+ result.append("\"");
+ if (!parent_)
+ result.append(", shape=box");
+ if (layer()) {
+ if (layer()->texture())
+ result.append(", color=green");
+ else
+ result.append(", color=red");
+
+ if (layer()->fills_bounds_opaquely())
+ result.append(", style=filled");
+ }
+ result.append("]\n");
+
+ // Link to parent.
+ if (parent_) {
+ char pp[kMaxPointerStringLength];
+
+ base::snprintf(pp, kMaxPointerStringLength, "%p", parent_);
+ result.append(" N");
+ result.append(pp+2);
+ result.append(" -> N");
+ result.append(p+2);
+ result.append("\n");
+ }
+
+ // Children.
+ for (int i = 0, count = view_with_children->child_count(); i < count; ++i)
+ result.append(view_with_children->child_at(i)->PrintViewGraph(false));
+
+ if (first)
+ result.append("}\n");
+
+ return result;
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// View, private:
+
+// DropInfo --------------------------------------------------------------------
+
+void View::DragInfo::Reset() {
+ possible_drag = false;
+ start_pt = gfx::Point();
+}
+
+void View::DragInfo::PossibleDrag(const gfx::Point& p) {
+ possible_drag = true;
+ start_pt = p;
+}
+
+// Painting --------------------------------------------------------------------
+
+void View::SchedulePaintBoundsChanged(SchedulePaintType type) {
+ // If we have a layer and the View's size did not change, we do not need to
+ // schedule any paints since the layer will be redrawn at its new location
+ // during the next Draw() cycle in the compositor.
+ if (!layer() || type == SCHEDULE_PAINT_SIZE_CHANGED) {
+ // Otherwise, if the size changes or we don't have a layer then we need to
+ // use SchedulePaint to invalidate the area occupied by the View.
+ SchedulePaint();
+ } else if (parent_ && type == SCHEDULE_PAINT_SIZE_SAME) {
+ // The compositor doesn't Draw() until something on screen changes, so
+ // if our position changes but nothing is being animated on screen, then
+ // tell the compositor to redraw the scene. We know layer() exists due to
+ // the above if clause.
+ layer()->ScheduleDraw();
+ }
+}
+
+void View::PaintCommon(gfx::Canvas* canvas) {
+ if (!IsVisible() || !painting_enabled_)
+ return;
+
+ {
+ // If the View we are about to paint requested the canvas to be flipped, we
+ // should change the transform appropriately.
+ // The canvas mirroring is undone once the View is done painting so that we
+ // don't pass the canvas with the mirrored transform to Views that didn't
+ // request the canvas to be flipped.
+ ScopedCanvas scoped(canvas);
+ if (FlipCanvasOnPaintForRTLUI()) {
+ canvas->Translate(gfx::Point(width(), 0));
+ canvas->Scale(-1, 1);
+ }
+
+ OnPaint(canvas);
+ }
+
+ PaintChildren(canvas);
+}
+
+// Tree operations -------------------------------------------------------------
+
+void View::DoRemoveChildView(View* view,
+ bool update_focus_cycle,
+ bool update_tool_tip,
+ bool delete_removed_view) {
+ DCHECK(view);
+ const Views::iterator i(std::find(children_.begin(), children_.end(), view));
+ scoped_ptr<View> view_to_be_deleted;
+ if (i != children_.end()) {
+ if (update_focus_cycle) {
+ // Let's remove the view from the focus traversal.
+ View* next_focusable = view->next_focusable_view_;
+ View* prev_focusable = view->previous_focusable_view_;
+ if (prev_focusable)
+ prev_focusable->next_focusable_view_ = next_focusable;
+ if (next_focusable)
+ next_focusable->previous_focusable_view_ = prev_focusable;
+ }
+
+ if (GetWidget())
+ UnregisterChildrenForVisibleBoundsNotification(view);
+ view->PropagateRemoveNotifications(this);
+ view->parent_ = NULL;
+ view->UpdateLayerVisibility();
+
+ if (delete_removed_view && view->parent_owned())
+ view_to_be_deleted.reset(view);
+
+ children_.erase(i);
+ }
+
+ if (update_tool_tip)
+ UpdateTooltip();
+
+ if (layout_manager_.get())
+ layout_manager_->ViewRemoved(this, view);
+}
+
+void View::PropagateRemoveNotifications(View* parent) {
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->PropagateRemoveNotifications(parent);
+
+ for (View* v = this; v; v = v->parent_)
+ v->ViewHierarchyChangedImpl(true, false, parent, this);
+}
+
+void View::PropagateAddNotifications(View* parent, View* child) {
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->PropagateAddNotifications(parent, child);
+ ViewHierarchyChangedImpl(true, true, parent, child);
+}
+
+void View::PropagateNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ internal::RootView* root_view) {
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->PropagateNativeViewHierarchyChanged(attached,
+ native_view,
+ root_view);
+ NativeViewHierarchyChanged(attached, native_view, root_view);
+}
+
+void View::ViewHierarchyChangedImpl(bool register_accelerators,
+ bool is_add,
+ View* parent,
+ View* child) {
+ if (register_accelerators) {
+ if (is_add) {
+ // If you get this registration, you are part of a subtree that has been
+ // added to the view hierarchy.
+ if (GetFocusManager()) {
+ RegisterPendingAccelerators();
+ } else {
+ // Delay accelerator registration until visible as we do not have
+ // focus manager until then.
+ accelerator_registration_delayed_ = true;
+ }
+ } else {
+ if (child == this)
+ UnregisterAccelerators(true);
+ }
+ }
+
+ if (is_add && layer() && !layer()->parent()) {
+ UpdateParentLayer();
+ } else if (!is_add && child == this) {
+ // Make sure the layers beloning to the subtree rooted at |child| get
+ // removed from layers that do not belong in the same subtree.
+ OrphanLayers();
+ }
+
+ ViewHierarchyChanged(is_add, parent, child);
+ parent->needs_layout_ = true;
+}
+
+// Size and disposition --------------------------------------------------------
+
+void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->PropagateVisibilityNotifications(start, is_visible);
+ VisibilityChangedImpl(start, is_visible);
+}
+
+void View::VisibilityChangedImpl(View* starting_from, bool is_visible) {
+ if (is_visible)
+ RegisterPendingAccelerators();
+ else
+ UnregisterAccelerators(true);
+ VisibilityChanged(starting_from, is_visible);
+}
+
+void View::BoundsChanged(const gfx::Rect& previous_bounds) {
+ if (IsVisible()) {
+ // Paint the new bounds.
+ SchedulePaintBoundsChanged(
+ bounds_.size() == previous_bounds.size() ? SCHEDULE_PAINT_SIZE_SAME :
+ SCHEDULE_PAINT_SIZE_CHANGED);
+ }
+
+ if (use_acceleration_when_possible) {
+ if (layer()) {
+ if (parent_) {
+ gfx::Point offset;
+ parent_->CalculateOffsetToAncestorWithLayer(&offset, NULL);
+ offset.Offset(x(), y());
+ layer()->SetBounds(gfx::Rect(offset, size()));
+ } else {
+ layer()->SetBounds(bounds_);
+ }
+ // TODO(beng): this seems redundant with the SchedulePaint at the top of
+ // this function. explore collapsing.
+ if (previous_bounds.size() != bounds_.size() &&
+ !layer()->layer_updated_externally()) {
+ // If our bounds have changed then we need to update the complete
+ // texture.
+ layer()->SchedulePaint(GetLocalBounds());
+ }
+ } else {
+ // If our bounds have changed, then any descendant layer bounds may
+ // have changed. Update them accordingly.
+ gfx::Point offset;
+ CalculateOffsetToAncestorWithLayer(&offset, NULL);
+ UpdateChildLayerBounds(offset);
+ }
+ }
+
+ OnBoundsChanged(previous_bounds);
+
+ if (previous_bounds.size() != size()) {
+ needs_layout_ = false;
+ Layout();
+ }
+
+ if (NeedsNotificationWhenVisibleBoundsChange())
+ OnVisibleBoundsChanged();
+
+ // Notify interested Views that visible bounds within the root view may have
+ // changed.
+ if (descendants_to_notify_.get()) {
+ for (Views::iterator i(descendants_to_notify_->begin());
+ i != descendants_to_notify_->end(); ++i) {
+ (*i)->OnVisibleBoundsChanged();
+ }
+ }
+}
+
+// static
+void View::RegisterChildrenForVisibleBoundsNotification(View* view) {
+ if (view->NeedsNotificationWhenVisibleBoundsChange())
+ view->RegisterForVisibleBoundsNotification();
+ for (int i = 0; i < view->child_count(); ++i)
+ RegisterChildrenForVisibleBoundsNotification(view->child_at(i));
+}
+
+// static
+void View::UnregisterChildrenForVisibleBoundsNotification(View* view) {
+ if (view->NeedsNotificationWhenVisibleBoundsChange())
+ view->UnregisterForVisibleBoundsNotification();
+ for (int i = 0; i < view->child_count(); ++i)
+ UnregisterChildrenForVisibleBoundsNotification(view->child_at(i));
+}
+
+void View::RegisterForVisibleBoundsNotification() {
+ if (registered_for_visible_bounds_notification_)
+ return;
+
+ registered_for_visible_bounds_notification_ = true;
+ for (View* ancestor = parent_; ancestor; ancestor = ancestor->parent_)
+ ancestor->AddDescendantToNotify(this);
+}
+
+void View::UnregisterForVisibleBoundsNotification() {
+ if (!registered_for_visible_bounds_notification_)
+ return;
+
+ registered_for_visible_bounds_notification_ = false;
+ for (View* ancestor = parent_; ancestor; ancestor = ancestor->parent_)
+ ancestor->RemoveDescendantToNotify(this);
+}
+
+void View::AddDescendantToNotify(View* view) {
+ DCHECK(view);
+ if (!descendants_to_notify_.get())
+ descendants_to_notify_.reset(new Views);
+ descendants_to_notify_->push_back(view);
+}
+
+void View::RemoveDescendantToNotify(View* view) {
+ DCHECK(view && descendants_to_notify_.get());
+ Views::iterator i(std::find(
+ descendants_to_notify_->begin(), descendants_to_notify_->end(), view));
+ DCHECK(i != descendants_to_notify_->end());
+ descendants_to_notify_->erase(i);
+ if (descendants_to_notify_->empty())
+ descendants_to_notify_.reset();
+}
+
+// Transformations -------------------------------------------------------------
+
+bool View::GetTransformRelativeTo(const View* ancestor,
+ ui::Transform* transform) const {
+ const View* p = this;
+
+ while (p && p != ancestor) {
+ transform->ConcatTransform(p->GetTransform());
+ transform->ConcatTranslate(static_cast<float>(p->GetMirroredX()),
+ static_cast<float>(p->y()));
+
+ p = p->parent_;
+ }
+
+ return p == ancestor;
+}
+
+// Coordinate conversion -------------------------------------------------------
+
+bool View::ConvertPointForAncestor(const View* ancestor,
+ gfx::Point* point) const {
+ ui::Transform trans;
+ // TODO(sad): Have some way of caching the transformation results.
+ bool result = GetTransformRelativeTo(ancestor, &trans);
+ gfx::Point3f p(*point);
+ trans.TransformPoint(p);
+ *point = p.AsPoint();
+ return result;
+}
+
+bool View::ConvertPointFromAncestor(const View* ancestor,
+ gfx::Point* point) const {
+ ui::Transform trans;
+ bool result = GetTransformRelativeTo(ancestor, &trans);
+ gfx::Point3f p(*point);
+ trans.TransformPointReverse(p);
+ *point = p.AsPoint();
+ return result;
+}
+
+// Accelerated painting --------------------------------------------------------
+
+void View::CreateLayer() {
+ // A new layer is being created for the view. So all the layers of the
+ // sub-tree can inherit the visibility of the corresponding view.
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->UpdateChildLayerVisibility(true);
+
+ layer_.reset(new ui::Layer());
+ layer_->set_delegate(this);
+#if !defined(NDEBUG)
+ layer_->set_name(GetClassName());
+#endif
+
+ UpdateParentLayers();
+ UpdateLayerVisibility();
+
+ // The new layer needs to be ordered in the layer tree according
+ // to the view tree. Children of this layer were added in order
+ // in UpdateParentLayers().
+ if (parent())
+ parent()->ReorderLayers();
+}
+
+void View::UpdateParentLayers() {
+ // Attach all top-level un-parented layers.
+ if (layer() && !layer()->parent()) {
+ UpdateParentLayer();
+ } else {
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->UpdateParentLayers();
+ }
+}
+
+void View::UpdateParentLayer() {
+ if (!layer())
+ return;
+
+ ui::Layer* parent_layer = NULL;
+ gfx::Point offset(x(), y());
+
+ // TODO(sad): The NULL check here for parent_ essentially is to check if this
+ // is the RootView. Instead of doing this, this function should be made
+ // virtual and overridden from the RootView.
+ if (parent_)
+ parent_->CalculateOffsetToAncestorWithLayer(&offset, &parent_layer);
+ else if (!parent_ && GetWidget())
+ GetWidget()->CalculateOffsetToAncestorWithLayer(&offset, &parent_layer);
+
+ ReparentLayer(offset, parent_layer);
+}
+
+void View::OrphanLayers() {
+ if (layer()) {
+ if (layer()->parent())
+ layer()->parent()->Remove(layer());
+
+ // The layer belonging to this View has already been orphaned. It is not
+ // necessary to orphan the child layers.
+ return;
+ }
+ for (int i = 0, count = child_count(); i < count; ++i)
+ child_at(i)->OrphanLayers();
+}
+
+void View::ReparentLayer(const gfx::Point& offset, ui::Layer* parent_layer) {
+ layer_->SetBounds(gfx::Rect(offset.x(), offset.y(), width(), height()));
+ DCHECK_NE(layer(), parent_layer);
+ if (parent_layer)
+ parent_layer->Add(layer());
+ layer_->SchedulePaint(GetLocalBounds());
+ MoveLayerToParent(layer(), gfx::Point());
+}
+
+void View::DestroyLayer() {
+ ui::Layer* new_parent = layer()->parent();
+ std::vector<ui::Layer*> children = layer()->children();
+ for (size_t i = 0; i < children.size(); ++i) {
+ layer()->Remove(children[i]);
+ if (new_parent)
+ new_parent->Add(children[i]);
+ }
+
+ layer_.reset();
+
+ if (new_parent)
+ ReorderLayers();
+
+ gfx::Point offset;
+ CalculateOffsetToAncestorWithLayer(&offset, NULL);
+ UpdateChildLayerBounds(offset);
+
+ SchedulePaint();
+}
+
+// Input -----------------------------------------------------------------------
+
+bool View::ProcessMousePressed(const MouseEvent& event, DragInfo* drag_info) {
+ const bool enabled = IsEnabled();
+ int drag_operations =
+ (enabled && event.IsOnlyLeftMouseButton() && HitTest(event.location())) ?
+ GetDragOperations(event.location()) : 0;
+ ContextMenuController* context_menu_controller = event.IsRightMouseButton() ?
+ context_menu_controller_ : 0;
+
+ const bool result = OnMousePressed(event);
+ // WARNING: we may have been deleted, don't use any View variables.
+
+ if (!enabled)
+ return result;
+
+ if (drag_operations != ui::DragDropTypes::DRAG_NONE) {
+ drag_info->PossibleDrag(event.location());
+ return true;
+ }
+ return !!context_menu_controller || result;
+}
+
+bool View::ProcessMouseDragged(const MouseEvent& event, DragInfo* drag_info) {
+ // Copy the field, that way if we're deleted after drag and drop no harm is
+ // done.
+ ContextMenuController* context_menu_controller = context_menu_controller_;
+ const bool possible_drag = drag_info->possible_drag;
+ if (possible_drag && ExceededDragThreshold(
+ drag_info->start_pt.x() - event.x(),
+ drag_info->start_pt.y() - event.y())) {
+ if (!drag_controller_ ||
+ drag_controller_->CanStartDragForView(
+ this, drag_info->start_pt, event.location()))
+ DoDrag(event, drag_info->start_pt);
+ } else {
+ if (OnMouseDragged(event))
+ return true;
+ // Fall through to return value based on context menu controller.
+ }
+ // WARNING: we may have been deleted.
+ return (context_menu_controller != NULL) || possible_drag;
+}
+
+void View::ProcessMouseReleased(const MouseEvent& event) {
+ if (context_menu_controller_ && event.IsOnlyRightMouseButton()) {
+ // Assume that if there is a context menu controller we won't be deleted
+ // from mouse released.
+ gfx::Point location(event.location());
+ OnMouseReleased(event);
+ if (HitTest(location)) {
+ ConvertPointToScreen(this, &location);
+ ShowContextMenu(location, true);
+ }
+ } else {
+ OnMouseReleased(event);
+ }
+ // WARNING: we may have been deleted.
+}
+
+ui::TouchStatus View::ProcessTouchEvent(const TouchEvent& event) {
+ // TODO(rjkroege): Implement a grab scheme similar to as as is found in
+ // MousePressed.
+ return OnTouchEvent(event);
+}
+
+// Accelerators ----------------------------------------------------------------
+
+void View::RegisterPendingAccelerators() {
+ if (!accelerators_.get() ||
+ registered_accelerator_count_ == accelerators_->size()) {
+ // No accelerators are waiting for registration.
+ return;
+ }
+
+ if (!GetWidget()) {
+ // The view is not yet attached to a widget, defer registration until then.
+ return;
+ }
+
+ accelerator_focus_manager_ = GetFocusManager();
+ if (!accelerator_focus_manager_) {
+ // Some crash reports seem to show that we may get cases where we have no
+ // focus manager (see bug #1291225). This should never be the case, just
+ // making sure we don't crash.
+
+ // TODO(jcampan): This fails for a view under NativeWidgetGtk with
+ // TYPE_CHILD. (see http://crbug.com/21335) reenable
+ // NOTREACHED assertion and verify accelerators works as
+ // expected.
+#if defined(OS_WIN)
+ NOTREACHED();
+#endif
+ return;
+ }
+ // Only register accelerators if we are visible.
+ if (!IsVisibleInRootView() || !GetWidget()->IsVisible())
+ return;
+ for (std::vector<ui::Accelerator>::const_iterator i(
+ accelerators_->begin() + registered_accelerator_count_);
+ i != accelerators_->end(); ++i) {
+ accelerator_focus_manager_->RegisterAccelerator(*i, this);
+ }
+ registered_accelerator_count_ = accelerators_->size();
+}
+
+void View::UnregisterAccelerators(bool leave_data_intact) {
+ if (!accelerators_.get())
+ return;
+
+ if (GetWidget()) {
+ if (accelerator_focus_manager_) {
+ // We may not have a FocusManager if the window containing us is being
+ // closed, in which case the FocusManager is being deleted so there is
+ // nothing to unregister.
+ accelerator_focus_manager_->UnregisterAccelerators(this);
+ accelerator_focus_manager_ = NULL;
+ }
+ if (!leave_data_intact) {
+ accelerators_->clear();
+ accelerators_.reset();
+ }
+ registered_accelerator_count_ = 0;
+ }
+}
+
+// Focus -----------------------------------------------------------------------
+
+void View::InitFocusSiblings(View* v, int index) {
+ int count = child_count();
+
+ if (count == 0) {
+ v->next_focusable_view_ = NULL;
+ v->previous_focusable_view_ = NULL;
+ } else {
+ if (index == count) {
+ // We are inserting at the end, but the end of the child list may not be
+ // the last focusable element. Let's try to find an element with no next
+ // focusable element to link to.
+ View* last_focusable_view = NULL;
+ for (Views::iterator i(children_.begin()); i != children_.end(); ++i) {
+ if (!(*i)->next_focusable_view_) {
+ last_focusable_view = *i;
+ break;
+ }
+ }
+ if (last_focusable_view == NULL) {
+ // Hum... there is a cycle in the focus list. Let's just insert ourself
+ // after the last child.
+ View* prev = children_[index - 1];
+ v->previous_focusable_view_ = prev;
+ v->next_focusable_view_ = prev->next_focusable_view_;
+ prev->next_focusable_view_->previous_focusable_view_ = v;
+ prev->next_focusable_view_ = v;
+ } else {
+ last_focusable_view->next_focusable_view_ = v;
+ v->next_focusable_view_ = NULL;
+ v->previous_focusable_view_ = last_focusable_view;
+ }
+ } else {
+ View* prev = children_[index]->GetPreviousFocusableView();
+ v->previous_focusable_view_ = prev;
+ v->next_focusable_view_ = children_[index];
+ if (prev)
+ prev->next_focusable_view_ = v;
+ children_[index]->previous_focusable_view_ = v;
+ }
+ }
+}
+
+// System events ---------------------------------------------------------------
+
+void View::PropagateThemeChanged() {
+ for (int i = child_count() - 1; i >= 0; --i)
+ child_at(i)->PropagateThemeChanged();
+ OnThemeChanged();
+}
+
+void View::PropagateLocaleChanged() {
+ for (int i = child_count() - 1; i >= 0; --i)
+ child_at(i)->PropagateLocaleChanged();
+ OnLocaleChanged();
+}
+
+// Tooltips --------------------------------------------------------------------
+
+void View::UpdateTooltip() {
+ Widget* widget = GetWidget();
+ // TODO(beng): The TooltipManager NULL check can be removed when we
+ // consolidate Init() methods and make views_unittests Init() all
+ // Widgets that it uses.
+ if (widget && widget->native_widget_private()->GetTooltipManager())
+ widget->native_widget_private()->GetTooltipManager()->UpdateTooltip();
+}
+
+// Drag and drop ---------------------------------------------------------------
+
+void View::DoDrag(const MouseEvent& event, const gfx::Point& press_pt) {
+ int drag_operations = GetDragOperations(press_pt);
+ if (drag_operations == ui::DragDropTypes::DRAG_NONE)
+ return;
+
+ OSExchangeData data;
+ WriteDragData(press_pt, &data);
+
+ // Message the RootView to do the drag and drop. That way if we're removed
+ // the RootView can detect it and avoid calling us back.
+ GetWidget()->RunShellDrag(this, data, drag_operations);
+}
+
+} // namespace views
diff --git a/ui/views/view.h b/ui/views/view.h
new file mode 100644
index 0000000..6e8eb28
--- /dev/null
+++ b/ui/views/view.h
@@ -0,0 +1,1440 @@
+// 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_VIEW_H_
+#define UI_VIEWS_VIEW_H_
+#pragma once
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/gfx/compositor/layer_delegate.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/rect.h"
+#include "ui/views/events/event.h"
+#include "views/background.h"
+#include "views/border.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_comptr.h"
+#endif
+
+using ui::OSExchangeData;
+
+namespace gfx {
+class Canvas;
+class Insets;
+class Path;
+}
+
+namespace ui {
+struct AccessibleViewState;
+class Compositor;
+class Layer;
+class TextInputClient;
+class Texture;
+class ThemeProvider;
+class Transform;
+enum TouchStatus;
+}
+
+#if defined(OS_WIN)
+class __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
+NativeViewAccessibilityWin;
+#endif
+
+namespace views {
+
+class Background;
+class Border;
+class ContextMenuController;
+class DragController;
+class FocusManager;
+class FocusTraversable;
+class InputMethod;
+class LayoutManager;
+class ScrollView;
+class Widget;
+
+namespace internal {
+class NativeWidgetView;
+class RootView;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View class
+//
+// A View is a rectangle within the views View hierarchy. It is the base
+// class for all Views.
+//
+// A View is a container of other Views (there is no such thing as a Leaf
+// View - makes code simpler, reduces type conversion headaches, design
+// mistakes etc)
+//
+// The View contains basic properties for sizing (bounds), layout (flex,
+// orientation, etc), painting of children and event dispatch.
+//
+// The View also uses a simple Box Layout Manager similar to XUL's
+// SprocketLayout system. Alternative Layout Managers implementing the
+// LayoutManager interface can be used to lay out children if required.
+//
+// It is up to the subclass to implement Painting and storage of subclass -
+// specific properties and functionality.
+//
+// Unless otherwise documented, views is not thread safe and should only be
+// accessed from the main thread.
+//
+/////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT View : public ui::LayerDelegate,
+ public ui::AcceleratorTarget {
+ public:
+ typedef std::vector<View*> Views;
+
+ // TO BE MOVED ---------------------------------------------------------------
+ // TODO(beng): These methods are to be moved to other files/classes.
+
+ // TODO(beng): delete
+ // Set whether this view is hottracked. A disabled view cannot be hottracked.
+ // If flag differs from the current value, SchedulePaint is invoked.
+ virtual void SetHotTracked(bool flag);
+
+ // TODO(beng): delete
+ // Returns whether the view is hot-tracked.
+ virtual bool IsHotTracked() const;
+
+ // Creation and lifetime -----------------------------------------------------
+
+ View();
+ virtual ~View();
+
+ // By default a View is owned by its parent unless specified otherwise here.
+ bool parent_owned() const { return parent_owned_; }
+ void set_parent_owned(bool parent_owned) { parent_owned_ = parent_owned; }
+
+ // Tree operations -----------------------------------------------------------
+
+ // Get the Widget that hosts this View, if any.
+ virtual const Widget* GetWidget() const;
+ virtual Widget* GetWidget();
+
+ // Adds |view| as a child of this view, optionally at |index|.
+ void AddChildView(View* view);
+ void AddChildViewAt(View* view, int index);
+
+ // Moves |view| to the specified |index|. A negative value for |index| moves
+ // the view at the end.
+ void ReorderChildView(View* view, int index);
+
+ // Removes |view| from this view. The view's parent will change to NULL.
+ void RemoveChildView(View* view);
+
+ // Removes all the children from this view. If |delete_children| is true,
+ // the views are deleted, unless marked as not parent owned.
+ void RemoveAllChildViews(bool delete_children);
+
+ // STL-style accessors.
+ Views::const_iterator children_begin() { return children_.begin(); }
+ Views::const_iterator children_end() { return children_.end(); }
+ Views::const_reverse_iterator children_rbegin() { return children_.rbegin(); }
+ Views::const_reverse_iterator children_rend() { return children_.rend(); }
+ int child_count() const { return static_cast<int>(children_.size()); }
+ bool has_children() const { return !children_.empty(); }
+
+ // Returns the child view at |index|.
+ const View* child_at(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK_LT(index, child_count());
+ return children_[index];
+ }
+ View* child_at(int index) {
+ return const_cast<View*>(const_cast<const View*>(this)->child_at(index));
+ }
+
+ // Returns the parent view.
+ const View* parent() const { return parent_; }
+ View* parent() { return parent_; }
+
+ // Returns true if |view| is contained within this View's hierarchy, even as
+ // an indirect descendant. Will return true if child is also this view.
+ bool Contains(const View* view) const;
+
+ // Returns the index of |view|, or -1 if |view| is not a child of this view.
+ int GetIndexOf(const View* view) const;
+
+ // Size and disposition ------------------------------------------------------
+ // Methods for obtaining and modifying the position and size of the view.
+ // Position is in the coordinate system of the view's parent.
+ // Position is NOT flipped for RTL. See "RTL positioning" for RTL-sensitive
+ // position accessors.
+ // Transformations are not applied on the size/position. For example, if
+ // bounds is (0, 0, 100, 100) and it is scaled by 0.5 along the X axis, the
+ // width will still be 100 (although when painted, it will be 50x50, painted
+ // at location (0, 0)).
+
+ void SetBounds(int x, int y, int width, int height);
+ void SetBoundsRect(const gfx::Rect& bounds);
+ void SetSize(const gfx::Size& size);
+ void SetPosition(const gfx::Point& position);
+ void SetX(int x);
+ void SetY(int y);
+
+ // No transformation is applied on the size or the locations.
+ const gfx::Rect& bounds() const { return bounds_; }
+ int x() const { return bounds_.x(); }
+ int y() const { return bounds_.y(); }
+ int width() const { return bounds_.width(); }
+ int height() const { return bounds_.height(); }
+ const gfx::Size& size() const { return bounds_.size(); }
+
+ // Returns the bounds of the content area of the view, i.e. the rectangle
+ // enclosed by the view's border.
+ gfx::Rect GetContentsBounds() const;
+
+ // Returns the bounds of the view in its own coordinates (i.e. position is
+ // 0, 0).
+ gfx::Rect GetLocalBounds() const;
+
+ // Returns the insets of the current border. If there is no border an empty
+ // insets is returned.
+ virtual gfx::Insets GetInsets() const;
+
+ // Returns the visible bounds of the receiver in the receivers coordinate
+ // system.
+ //
+ // When traversing the View hierarchy in order to compute the bounds, the
+ // function takes into account the mirroring setting and transformation for
+ // each View and therefore it will return the mirrored and transformed version
+ // of the visible bounds if need be.
+ gfx::Rect GetVisibleBounds() const;
+
+ // Return the bounds of the View in screen coordinate system.
+ gfx::Rect GetScreenBounds() const;
+
+ // Returns the baseline of this view, or -1 if this view has no baseline. The
+ // return value is relative to the preferred height.
+ virtual int GetBaseline() const;
+
+ // Get the size the View would like to be, if enough space were available.
+ virtual gfx::Size GetPreferredSize();
+
+ // Convenience method that sizes this view to its preferred size.
+ void SizeToPreferredSize();
+
+ // Gets the minimum size of the view. View's implementation invokes
+ // GetPreferredSize.
+ virtual gfx::Size GetMinimumSize();
+
+ // Return the height necessary to display this view with the provided width.
+ // View's implementation returns the value from getPreferredSize.cy.
+ // Override if your View's preferred height depends upon the width (such
+ // as with Labels).
+ virtual int GetHeightForWidth(int w);
+
+ // Set whether the receiving view is visible. Painting is scheduled as needed
+ virtual void SetVisible(bool visible);
+
+ // Return whether a view is visible
+ virtual bool IsVisible() const;
+
+ // Return whether a view and its ancestors are visible. Returns true if the
+ // path from this view to the root view is visible.
+ virtual bool IsVisibleInRootView() const;
+
+ // Set whether this view is enabled. A disabled view does not receive keyboard
+ // or mouse inputs. If flag differs from the current value, SchedulePaint is
+ // invoked.
+ void SetEnabled(bool enabled);
+
+ // Returns whether the view is enabled.
+ virtual bool IsEnabled() const;
+
+ // This indicates that the view completely fills its bounds in an opaque
+ // color. This doesn't affect compositing but is a hint to the compositor to
+ // optimize painting.
+ // Note that this method does not implicitly create a layer if one does not
+ // already exist for the View, but is a no-op in that case.
+ void SetFillsBoundsOpaquely(bool fills_bounds_opaquely);
+
+ // Transformations -----------------------------------------------------------
+
+ // Methods for setting transformations for a view (e.g. rotation, scaling).
+
+ const ui::Transform& GetTransform() const;
+
+ // Clipping parameters. Clipping happens from the right and/or bottom. The
+ // clipping amount is in parent's coordinate system, as in, if the view is
+ // rotated, then the clipping will be applied after the rotation (and other
+ // transformations, if any).
+ void set_clip_x(float x) { clip_x_ = x; }
+ void set_clip_y(float y) { clip_y_ = y; }
+ void set_clip(float x, float y) { clip_x_ = x; clip_y_ = y; }
+
+ // Sets the transform to the supplied transform.
+ void SetTransform(const ui::Transform& transform);
+
+ // Sets whether this view paints to a layer. A view paints to a layer if
+ // either of the following are true:
+ // . the view has a non-identity transform.
+ // . SetPaintToLayer(true) has been invoked.
+ // View creates the Layer only when it exists in a Widget with a non-NULL
+ // Compositor.
+ void SetPaintToLayer(bool paint_to_layer);
+
+ const ui::Layer* layer() const { return layer_.get(); }
+ ui::Layer* layer() { return layer_.get(); }
+
+ // RTL positioning -----------------------------------------------------------
+
+ // Methods for accessing the bounds and position of the view, relative to its
+ // parent. The position returned is mirrored if the parent view is using a RTL
+ // layout.
+ //
+ // NOTE: in the vast majority of the cases, the mirroring implementation is
+ // transparent to the View subclasses and therefore you should use the
+ // bounds() accessor instead.
+ gfx::Rect GetMirroredBounds() const;
+ gfx::Point GetMirroredPosition() const;
+ int GetMirroredX() const;
+
+ // Given a rectangle specified in this View's coordinate system, the function
+ // computes the 'left' value for the mirrored rectangle within this View. If
+ // the View's UI layout is not right-to-left, then bounds.x() is returned.
+ //
+ // UI mirroring is transparent to most View subclasses and therefore there is
+ // no need to call this routine from anywhere within your subclass
+ // implementation.
+ int GetMirroredXForRect(const gfx::Rect& rect) const;
+
+ // Given the X coordinate of a point inside the View, this function returns
+ // the mirrored X coordinate of the point if the View's UI layout is
+ // right-to-left. If the layout is left-to-right, the same X coordinate is
+ // returned.
+ //
+ // Following are a few examples of the values returned by this function for
+ // a View with the bounds {0, 0, 100, 100} and a right-to-left layout:
+ //
+ // GetMirroredXCoordinateInView(0) -> 100
+ // GetMirroredXCoordinateInView(20) -> 80
+ // GetMirroredXCoordinateInView(99) -> 1
+ int GetMirroredXInView(int x) const;
+
+ // Given a X coordinate and a width inside the View, this function returns
+ // the mirrored X coordinate if the View's UI layout is right-to-left. If the
+ // layout is left-to-right, the same X coordinate is returned.
+ //
+ // Following are a few examples of the values returned by this function for
+ // a View with the bounds {0, 0, 100, 100} and a right-to-left layout:
+ //
+ // GetMirroredXCoordinateInView(0, 10) -> 90
+ // GetMirroredXCoordinateInView(20, 20) -> 60
+ int GetMirroredXWithWidthInView(int x, int w) const;
+
+ // Layout --------------------------------------------------------------------
+
+ // Lay out the child Views (set their bounds based on sizing heuristics
+ // specific to the current Layout Manager)
+ virtual void Layout();
+
+ // TODO(beng): I think we should remove this.
+ // Mark this view and all parents to require a relayout. This ensures the
+ // next call to Layout() will propagate to this view, even if the bounds of
+ // parent views do not change.
+ void InvalidateLayout();
+
+ // Gets/Sets the Layout Manager used by this view to size and place its
+ // children.
+ // The LayoutManager is owned by the View and is deleted when the view is
+ // deleted, or when a new LayoutManager is installed.
+ LayoutManager* GetLayoutManager() const;
+ void SetLayoutManager(LayoutManager* layout);
+
+ // Attributes ----------------------------------------------------------------
+
+ // The view class name.
+ static const char kViewClassName[];
+
+ // Return the receiving view's class name. A view class is a string which
+ // uniquely identifies the view class. It is intended to be used as a way to
+ // find out during run time if a view can be safely casted to a specific view
+ // subclass. The default implementation returns kViewClassName.
+ virtual std::string GetClassName() const;
+
+ // Returns the first ancestor, starting at this, whose class name is |name|.
+ // Returns null if no ancestor has the class name |name|.
+ View* GetAncestorWithClassName(const std::string& name);
+
+ // Recursively descends the view tree starting at this view, and returns
+ // the first child that it encounters that has the given ID.
+ // Returns NULL if no matching child view is found.
+ virtual const View* GetViewByID(int id) const;
+ virtual View* GetViewByID(int id);
+
+ // Gets and sets the ID for this view. ID should be unique within the subtree
+ // that you intend to search for it. 0 is the default ID for views.
+ int id() const { return id_; }
+ void set_id(int id) { id_ = id; }
+
+ // A group id is used to tag views which are part of the same logical group.
+ // Focus can be moved between views with the same group using the arrow keys.
+ // Groups are currently used to implement radio button mutual exclusion.
+ // The group id is immutable once it's set.
+ void SetGroup(int gid);
+ // Returns the group id of the view, or -1 if the id is not set yet.
+ int GetGroup() const;
+
+ // If this returns true, the views from the same group can each be focused
+ // when moving focus with the Tab/Shift-Tab key. If this returns false,
+ // only the selected view from the group (obtained with
+ // GetSelectedViewForGroup()) is focused.
+ virtual bool IsGroupFocusTraversable() const;
+
+ // Fills |views| with all the available views which belong to the provided
+ // |group|.
+ void GetViewsInGroup(int group, Views* views);
+
+ // Returns the View that is currently selected in |group|.
+ // The default implementation simply returns the first View found for that
+ // group.
+ virtual View* GetSelectedViewForGroup(int group);
+
+ // Coordinate conversion -----------------------------------------------------
+
+ // Note that the utility coordinate conversions functions always operate on
+ // the mirrored position of the child Views if the parent View uses a
+ // right-to-left UI layout.
+
+ // Convert a point from the coordinate system of one View to another.
+ //
+ // |source| and |target| must be in the same widget, but doesn't need to be in
+ // the same view hierarchy.
+ // |source| can be NULL in which case it means the screen coordinate system.
+ static void ConvertPointToView(const View* source,
+ const View* target,
+ gfx::Point* point);
+
+ // Convert a point from a View's coordinate system to that of its Widget.
+ static void ConvertPointToWidget(const View* src, gfx::Point* point);
+
+ // Convert a point from the coordinate system of a View's Widget to that
+ // View's coordinate system.
+ static void ConvertPointFromWidget(const View* dest, gfx::Point* p);
+
+ // Convert a point from a View's coordinate system to that of the screen.
+ static void ConvertPointToScreen(const View* src, gfx::Point* point);
+
+ // Applies transformation on the rectangle, which is in the view's coordinate
+ // system, to convert it into the parent's coordinate system.
+ gfx::Rect ConvertRectToParent(const gfx::Rect& rect) const;
+
+ // Converts a rectangle from this views coordinate system to its widget
+ // coordinate system.
+ gfx::Rect ConvertRectToWidget(const gfx::Rect& rect) const;
+
+ // Painting ------------------------------------------------------------------
+
+ // Mark all or part of the View's bounds as dirty (needing repaint).
+ // |r| is in the View's coordinates.
+ // Rectangle |r| should be in the view's coordinate system. The
+ // transformations are applied to it to convert it into the parent coordinate
+ // system before propagating SchedulePaint up the view hierarchy.
+ // TODO(beng): Make protected.
+ virtual void SchedulePaint();
+ virtual void SchedulePaintInRect(const gfx::Rect& r);
+
+ // Called by the framework to paint a View. Performs translation and clipping
+ // for View coordinates and language direction as required, allows the View
+ // to paint itself via the various OnPaint*() event handlers and then paints
+ // the hierarchy beneath it.
+ virtual void Paint(gfx::Canvas* canvas);
+
+ // The background object is owned by this object and may be NULL.
+ void set_background(Background* b) { background_.reset(b); }
+ const Background* background() const { return background_.get(); }
+ Background* background() { return background_.get(); }
+
+ // The border object is owned by this object and may be NULL.
+ void set_border(Border* b) { border_.reset(b); }
+ const Border* border() const { return border_.get(); }
+ Border* border() { return border_.get(); }
+
+ // Get the theme provider from the parent widget.
+ virtual ui::ThemeProvider* GetThemeProvider() const;
+
+ // RTL painting --------------------------------------------------------------
+
+ // This method determines whether the gfx::Canvas object passed to
+ // View::Paint() needs to be transformed such that anything drawn on the
+ // canvas object during View::Paint() is flipped horizontally.
+ //
+ // By default, this function returns false (which is the initial value of
+ // |flip_canvas_on_paint_for_rtl_ui_|). View subclasses that need to paint on
+ // a flipped gfx::Canvas when the UI layout is right-to-left need to call
+ // EnableCanvasFlippingForRTLUI().
+ bool FlipCanvasOnPaintForRTLUI() const {
+ return flip_canvas_on_paint_for_rtl_ui_ ? base::i18n::IsRTL() : false;
+ }
+
+ // Enables or disables flipping of the gfx::Canvas during View::Paint().
+ // Note that if canvas flipping is enabled, the canvas will be flipped only
+ // if the UI layout is right-to-left; that is, the canvas will be flipped
+ // only if base::i18n::IsRTL() returns true.
+ //
+ // Enabling canvas flipping is useful for leaf views that draw a bitmap that
+ // needs to be flipped horizontally when the UI layout is right-to-left
+ // (views::Button, for example). This method is helpful for such classes
+ // because their drawing logic stays the same and they can become agnostic to
+ // the UI directionality.
+ void EnableCanvasFlippingForRTLUI(bool enable) {
+ flip_canvas_on_paint_for_rtl_ui_ = enable;
+ }
+
+ // Accelerated painting ------------------------------------------------------
+
+ // Enable/Disable accelerated compositing.
+ static void set_use_acceleration_when_possible(bool use);
+ static bool get_use_acceleration_when_possible();
+
+ // Input ---------------------------------------------------------------------
+ // The points (and mouse locations) in the following functions are in the
+ // view's coordinates, except for a RootView.
+
+ // Returns the deepest visible descendant that contains the specified point.
+ virtual View* GetEventHandlerForPoint(const gfx::Point& point);
+
+ // Return the cursor that should be used for this view or the default cursor.
+ // The event location is in the receiver's coordinate system. The caller is
+ // responsible for managing the lifetime of the returned object, though that
+ // lifetime may vary from platform to platform. On Windows, the cursor is a
+ // shared resource, but Gtk destroys the returned cursor after setting it.
+ virtual gfx::NativeCursor GetCursor(const MouseEvent& event);
+
+ // Convenience to test whether a point is within this view's bounds
+ virtual bool HitTest(const gfx::Point& l) const;
+
+ // This method is invoked when the user clicks on this view.
+ // The provided event is in the receiver's coordinate system.
+ //
+ // Return true if you processed the event and want to receive subsequent
+ // MouseDraggged and MouseReleased events. This also stops the event from
+ // bubbling. If you return false, the event will bubble through parent
+ // views.
+ //
+ // If you remove yourself from the tree while processing this, event bubbling
+ // stops as if you returned true, but you will not receive future events.
+ // The return value is ignored in this case.
+ //
+ // Default implementation returns true if a ContextMenuController has been
+ // set, false otherwise. Override as needed.
+ //
+ virtual bool OnMousePressed(const MouseEvent& event);
+
+ // This method is invoked when the user clicked on this control.
+ // and is still moving the mouse with a button pressed.
+ // The provided event is in the receiver's coordinate system.
+ //
+ // Return true if you processed the event and want to receive
+ // subsequent MouseDragged and MouseReleased events.
+ //
+ // Default implementation returns true if a ContextMenuController has been
+ // set, false otherwise. Override as needed.
+ //
+ virtual bool OnMouseDragged(const MouseEvent& event);
+
+ // This method is invoked when the user releases the mouse
+ // button. The event is in the receiver's coordinate system.
+ //
+ // Default implementation notifies the ContextMenuController is appropriate.
+ // Subclasses that wish to honor the ContextMenuController should invoke
+ // super.
+ virtual void OnMouseReleased(const MouseEvent& event);
+
+ // This method is invoked when the mouse press/drag was canceled by a
+ // system/user gesture.
+ virtual void OnMouseCaptureLost();
+
+ // This method is invoked when the mouse is above this control
+ // The event is in the receiver's coordinate system.
+ //
+ // Default implementation does nothing. Override as needed.
+ virtual void OnMouseMoved(const MouseEvent& event);
+
+ // This method is invoked when the mouse enters this control.
+ //
+ // Default implementation does nothing. Override as needed.
+ virtual void OnMouseEntered(const MouseEvent& event);
+
+ // This method is invoked when the mouse exits this control
+ // The provided event location is always (0, 0)
+ // Default implementation does nothing. Override as needed.
+ virtual void OnMouseExited(const MouseEvent& event);
+
+ // This method is invoked for each touch event. Default implementation
+ // does nothing. Override as needed.
+ virtual ui::TouchStatus OnTouchEvent(const TouchEvent& event);
+
+ // Set the MouseHandler for a drag session.
+ //
+ // A drag session is a stream of mouse events starting
+ // with a MousePressed event, followed by several MouseDragged
+ // events and finishing with a MouseReleased event.
+ //
+ // This method should be only invoked while processing a
+ // MouseDragged or MousePressed event.
+ //
+ // All further mouse dragged and mouse up events will be sent
+ // the MouseHandler, even if it is reparented to another window.
+ //
+ // The MouseHandler is automatically cleared when the control
+ // comes back from processing the MouseReleased event.
+ //
+ // Note: if the mouse handler is no longer connected to a
+ // view hierarchy, events won't be sent.
+ //
+ virtual void SetMouseHandler(View* new_mouse_handler);
+
+ // Invoked when a key is pressed or released.
+ // Subclasser should return true if the event has been processed and false
+ // otherwise. If the event has not been processed, the parent will be given a
+ // chance.
+ virtual bool OnKeyPressed(const KeyEvent& event);
+ virtual bool OnKeyReleased(const KeyEvent& event);
+
+ // Invoked when the user uses the mousewheel. Implementors should return true
+ // if the event has been processed and false otherwise. This message is sent
+ // if the view is focused. If the event has not been processed, the parent
+ // will be given a chance.
+ virtual bool OnMouseWheel(const MouseWheelEvent& event);
+
+ // Returns the View's TextInputClient instance or NULL if the View doesn't
+ // support text input.
+ virtual ui::TextInputClient* GetTextInputClient();
+
+ // Convenience method to retrieve the InputMethod associated with the
+ // Widget that contains this view. Returns NULL if this view is not part of a
+ // view hierarchy with a Widget.
+ virtual InputMethod* GetInputMethod();
+
+ // Accelerators --------------------------------------------------------------
+
+ // Sets a keyboard accelerator for that view. When the user presses the
+ // accelerator key combination, the AcceleratorPressed method is invoked.
+ // Note that you can set multiple accelerators for a view by invoking this
+ // method several times.
+ virtual void AddAccelerator(const ui::Accelerator& accelerator);
+
+ // Removes the specified accelerator for this view.
+ virtual void RemoveAccelerator(const ui::Accelerator& accelerator);
+
+ // Removes all the keyboard accelerators for this view.
+ virtual void ResetAccelerators();
+
+ // Overridden from AcceleratorTarget:
+ virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
+
+ // Focus ---------------------------------------------------------------------
+
+ // Returns whether this view currently has the focus.
+ virtual bool HasFocus() const;
+
+ // Returns the view that should be selected next when pressing Tab.
+ View* GetNextFocusableView();
+ const View* GetNextFocusableView() const;
+
+ // Returns the view that should be selected next when pressing Shift-Tab.
+ View* GetPreviousFocusableView();
+
+ // Sets the component that should be selected next when pressing Tab, and
+ // makes the current view the precedent view of the specified one.
+ // Note that by default views are linked in the order they have been added to
+ // their container. Use this method if you want to modify the order.
+ // IMPORTANT NOTE: loops in the focus hierarchy are not supported.
+ void SetNextFocusableView(View* view);
+
+ // Sets whether this view can accept the focus.
+ // Note that this is false by default so that a view used as a container does
+ // not get the focus.
+ void set_focusable(bool focusable) { focusable_ = focusable; }
+
+ // Returns true if the view is focusable (IsFocusable) and visible in the root
+ // view. See also IsFocusable.
+ bool IsFocusableInRootView() const;
+
+ // Return whether this view is focusable when the user requires full keyboard
+ // access, even though it may not be normally focusable.
+ bool IsAccessibilityFocusableInRootView() const;
+
+ // Set whether this view can be made focusable if the user requires
+ // full keyboard access, even though it's not normally focusable.
+ // Note that this is false by default.
+ void set_accessibility_focusable(bool accessibility_focusable) {
+ accessibility_focusable_ = accessibility_focusable;
+ }
+
+ // Convenience method to retrieve the FocusManager associated with the
+ // Widget that contains this view. This can return NULL if this view is not
+ // part of a view hierarchy with a Widget.
+ virtual FocusManager* GetFocusManager();
+ virtual const FocusManager* GetFocusManager() const;
+
+ // Request the keyboard focus. The receiving view will become the
+ // focused view.
+ virtual void RequestFocus();
+
+ // Invoked when a view is about to be requested for focus due to the focus
+ // traversal. Reverse is this request was generated going backward
+ // (Shift-Tab).
+ virtual void AboutToRequestFocusFromTabTraversal(bool reverse) { }
+
+ // Invoked when a key is pressed before the key event is processed (and
+ // potentially eaten) by the focus manager for tab traversal, accelerators and
+ // other focus related actions.
+ // The default implementation returns false, ensuring that tab traversal and
+ // accelerators processing is performed.
+ // Subclasses should return true if they want to process the key event and not
+ // have it processed as an accelerator (if any) or as a tab traversal (if the
+ // key event is for the TAB key). In that case, OnKeyPressed will
+ // subsequently be invoked for that event.
+ virtual bool SkipDefaultKeyEventProcessing(const KeyEvent& event);
+
+ // Subclasses that contain traversable children that are not directly
+ // accessible through the children hierarchy should return the associated
+ // FocusTraversable for the focus traversal to work properly.
+ virtual FocusTraversable* GetFocusTraversable();
+
+ // Subclasses that can act as a "pane" must implement their own
+ // FocusTraversable to keep the focus trapped within the pane.
+ // If this method returns an object, any view that's a direct or
+ // indirect child of this view will always use this FocusTraversable
+ // rather than the one from the widget.
+ virtual FocusTraversable* GetPaneFocusTraversable();
+
+ // Tooltips ------------------------------------------------------------------
+
+ // Gets the tooltip for this View. If the View does not have a tooltip,
+ // return false. If the View does have a tooltip, copy the tooltip into
+ // the supplied string and return true.
+ // Any time the tooltip text that a View is displaying changes, it must
+ // invoke TooltipTextChanged.
+ // |p| provides the coordinates of the mouse (relative to this view).
+ virtual bool GetTooltipText(const gfx::Point& p, string16* tooltip) const;
+
+ // Returns the location (relative to this View) for the text on the tooltip
+ // to display. If false is returned (the default), the tooltip is placed at
+ // a default position.
+ virtual bool GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) const;
+
+ // Context menus -------------------------------------------------------------
+
+ // Sets the ContextMenuController. Setting this to non-null makes the View
+ // process mouse events.
+ ContextMenuController* context_menu_controller() {
+ return context_menu_controller_;
+ }
+ void set_context_menu_controller(ContextMenuController* menu_controller) {
+ context_menu_controller_ = menu_controller;
+ }
+
+ // Provides default implementation for context menu handling. The default
+ // implementation calls the ShowContextMenu of the current
+ // ContextMenuController (if it is not NULL). Overridden in subclassed views
+ // to provide right-click menu display triggerd by the keyboard (i.e. for the
+ // Chrome toolbar Back and Forward buttons). No source needs to be specified,
+ // as it is always equal to the current View.
+ virtual void ShowContextMenu(const gfx::Point& p,
+ bool is_mouse_gesture);
+
+ // Drag and drop -------------------------------------------------------------
+
+ DragController* drag_controller() { return drag_controller_; }
+ void set_drag_controller(DragController* drag_controller) {
+ drag_controller_ = drag_controller;
+ }
+
+ // During a drag and drop session when the mouse moves the view under the
+ // mouse is queried for the drop types it supports by way of the
+ // GetDropFormats methods. If the view returns true and the drag site can
+ // provide data in one of the formats, the view is asked if the drop data
+ // is required before any other drop events are sent. Once the
+ // data is available the view is asked if it supports the drop (by way of
+ // the CanDrop method). If a view returns true from CanDrop,
+ // OnDragEntered is sent to the view when the mouse first enters the view,
+ // as the mouse moves around within the view OnDragUpdated is invoked.
+ // If the user releases the mouse over the view and OnDragUpdated returns a
+ // valid drop, then OnPerformDrop is invoked. If the mouse moves outside the
+ // view or over another view that wants the drag, OnDragExited is invoked.
+ //
+ // Similar to mouse events, the deepest view under the mouse is first checked
+ // if it supports the drop (Drop). If the deepest view under
+ // the mouse does not support the drop, the ancestors are walked until one
+ // is found that supports the drop.
+
+ // Override and return the set of formats that can be dropped on this view.
+ // |formats| is a bitmask of the formats defined bye OSExchangeData::Format.
+ // The default implementation returns false, which means the view doesn't
+ // support dropping.
+ virtual bool GetDropFormats(
+ int* formats,
+ std::set<OSExchangeData::CustomFormat>* custom_formats);
+
+ // Override and return true if the data must be available before any drop
+ // methods should be invoked. The default is false.
+ virtual bool AreDropTypesRequired();
+
+ // A view that supports drag and drop must override this and return true if
+ // data contains a type that may be dropped on this view.
+ virtual bool CanDrop(const OSExchangeData& data);
+
+ // OnDragEntered is invoked when the mouse enters this view during a drag and
+ // drop session and CanDrop returns true. This is immediately
+ // followed by an invocation of OnDragUpdated, and eventually one of
+ // OnDragExited or OnPerformDrop.
+ virtual void OnDragEntered(const DropTargetEvent& event);
+
+ // Invoked during a drag and drop session while the mouse is over the view.
+ // This should return a bitmask of the DragDropTypes::DragOperation supported
+ // based on the location of the event. Return 0 to indicate the drop should
+ // not be accepted.
+ virtual int OnDragUpdated(const DropTargetEvent& event);
+
+ // Invoked during a drag and drop session when the mouse exits the views, or
+ // when the drag session was canceled and the mouse was over the view.
+ virtual void OnDragExited();
+
+ // Invoked during a drag and drop session when OnDragUpdated returns a valid
+ // operation and the user release the mouse.
+ virtual int OnPerformDrop(const DropTargetEvent& event);
+
+ // Invoked from DoDrag after the drag completes. This implementation does
+ // nothing, and is intended for subclasses to do cleanup.
+ virtual void OnDragDone();
+
+ // Returns true if the mouse was dragged enough to start a drag operation.
+ // delta_x and y are the distance the mouse was dragged.
+ static bool ExceededDragThreshold(int delta_x, int delta_y);
+
+ // Accessibility -------------------------------------------------------------
+
+ // Modifies |state| to reflect the current accessible state of this view.
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) { }
+
+ // Returns an instance of the native accessibility interface for this view.
+ virtual gfx::NativeViewAccessible GetNativeViewAccessible();
+
+ // Scrolling -----------------------------------------------------------------
+ // TODO(beng): Figure out if this can live somewhere other than View, i.e.
+ // closer to ScrollView.
+
+ // Scrolls the specified region, in this View's coordinate system, to be
+ // visible. View's implementation passes the call onto the parent View (after
+ // adjusting the coordinates). It is up to views that only show a portion of
+ // the child view, such as Viewport, to override appropriately.
+ virtual void ScrollRectToVisible(const gfx::Rect& rect);
+
+ // The following methods are used by ScrollView to determine the amount
+ // to scroll relative to the visible bounds of the view. For example, a
+ // return value of 10 indicates the scrollview should scroll 10 pixels in
+ // the appropriate direction.
+ //
+ // Each method takes the following parameters:
+ //
+ // is_horizontal: if true, scrolling is along the horizontal axis, otherwise
+ // the vertical axis.
+ // is_positive: if true, scrolling is by a positive amount. Along the
+ // vertical axis scrolling by a positive amount equates to
+ // scrolling down.
+ //
+ // The return value should always be positive and gives the number of pixels
+ // to scroll. ScrollView interprets a return value of 0 (or negative)
+ // to scroll by a default amount.
+ //
+ // See VariableRowHeightScrollHelper and FixedRowHeightScrollHelper for
+ // implementations of common cases.
+ virtual int GetPageScrollIncrement(ScrollView* scroll_view,
+ bool is_horizontal, bool is_positive);
+ virtual int GetLineScrollIncrement(ScrollView* scroll_view,
+ bool is_horizontal, bool is_positive);
+
+ protected:
+ // Size and disposition ------------------------------------------------------
+
+ // Override to be notified when the bounds of the view have changed.
+ virtual void OnBoundsChanged(const gfx::Rect& previous_bounds);
+
+ // Called when the preferred size of a child view changed. This gives the
+ // parent an opportunity to do a fresh layout if that makes sense.
+ virtual void ChildPreferredSizeChanged(View* child) {}
+
+ // Invalidates the layout and calls ChildPreferredSizeChanged on the parent
+ // if there is one. Be sure to call View::PreferredSizeChanged when
+ // overriding such that the layout is properly invalidated.
+ virtual void PreferredSizeChanged();
+
+ // Override returning true when the view needs to be notified when its visible
+ // bounds relative to the root view may have changed. Only used by
+ // NativeViewHost.
+ virtual bool NeedsNotificationWhenVisibleBoundsChange() const;
+
+ // Notification that this View's visible bounds relative to the root view may
+ // have changed. The visible bounds are the region of the View not clipped by
+ // its ancestors. This is used for clipping NativeViewHost.
+ virtual void OnVisibleBoundsChanged();
+
+ // Override to be notified when the enabled state of this View has
+ // changed. The default implementation calls SchedulePaint() on this View.
+ virtual void OnEnabledChanged();
+
+ // Tree operations -----------------------------------------------------------
+
+ // This method is invoked when the tree changes.
+ //
+ // When a view is removed, it is invoked for all children and grand
+ // children. For each of these views, a notification is sent to the
+ // view and all parents.
+ //
+ // When a view is added, a notification is sent to the view, all its
+ // parents, and all its children (and grand children)
+ //
+ // Default implementation does nothing. Override to perform operations
+ // required when a view is added or removed from a view hierarchy
+ //
+ // parent is the new or old parent. Child is the view being added or
+ // removed.
+ //
+ virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
+
+ // When SetVisible() changes the visibility of a view, this method is
+ // invoked for that view as well as all the children recursively.
+ virtual void VisibilityChanged(View* starting_from, bool is_visible);
+
+ // Called when the native view hierarchy changed.
+ // |attached| is true if that view has been attached to a new NativeView
+ // hierarchy, false if it has been detached.
+ // |native_view| is the NativeView this view was attached/detached from, and
+ // |root_view| is the root view associated with the NativeView.
+ // Views created without a native view parent don't have a focus manager.
+ // When this function is called they could do the processing that requires
+ // it - like registering accelerators, for example.
+ virtual void NativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ internal::RootView* root_view);
+
+ // Painting ------------------------------------------------------------------
+
+ // Responsible for calling Paint() on child Views. Override to control the
+ // order child Views are painted.
+ virtual void PaintChildren(gfx::Canvas* canvas);
+
+ // Override to provide rendering in any part of the View's bounds. Typically
+ // this is the "contents" of the view. If you override this method you will
+ // have to call the subsequent OnPaint*() methods manually.
+ virtual void OnPaint(gfx::Canvas* canvas);
+
+ // Override to paint a background before any content is drawn. Typically this
+ // is done if you are satisfied with a default OnPaint handler but wish to
+ // supply a different background.
+ virtual void OnPaintBackground(gfx::Canvas* canvas);
+
+ // Override to paint a border not specified by SetBorder().
+ virtual void OnPaintBorder(gfx::Canvas* canvas);
+
+ // Override to paint a focus border (usually a dotted rectangle) around
+ // relevant contents.
+ virtual void OnPaintFocusBorder(gfx::Canvas* canvas);
+
+ // Accelerated painting ------------------------------------------------------
+
+ // This creates a layer for the view, if one does not exist. It then
+ // passes the texture to a layer associated with the view. While an external
+ // texture is set, the view will not update the layer contents.
+ //
+ // |texture| cannot be NULL.
+ //
+ // Returns false if it cannot create a layer to which to assign the texture.
+ bool SetExternalTexture(ui::Texture* texture);
+
+ // Returns the offset from this view to the nearest ancestor with a layer.
+ // If |ancestor| is non-NULL it is set to the nearest ancestor with a layer.
+ virtual void CalculateOffsetToAncestorWithLayer(
+ gfx::Point* offset,
+ ui::Layer** layer_parent);
+
+ // If this view has a layer, the layer is reparented to |parent_layer| and its
+ // bounds is set based on |point|. If this view does not have a layer, then
+ // recurses through all children. This is used when adding a layer to an
+ // existing view to make sure all descendants that have layers are parented to
+ // the right layer.
+ virtual void MoveLayerToParent(ui::Layer* parent_layer,
+ const gfx::Point& point);
+
+ // Called to update the bounds of any child layers within this View's
+ // hierarchy when something happens to the hierarchy.
+ virtual void UpdateChildLayerBounds(const gfx::Point& offset);
+
+ // Overridden from ui::LayerDelegate:
+ virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
+
+ // Finds the layer that this view paints to (it may belong to an ancestor
+ // view), then reorders the immediate children of that layer to match the
+ // order of the view tree.
+ virtual void ReorderLayers();
+
+ // This reorders the immediate children of |*parent_layer| to match the
+ // order of the view tree.
+ virtual void ReorderChildLayers(ui::Layer* parent_layer);
+
+ // Input ---------------------------------------------------------------------
+
+ // Called by HitTest to see if this View has a custom hit test mask. If the
+ // return value is true, GetHitTestMask will be called to obtain the mask.
+ // Default value is false, in which case the View will hit-test against its
+ // bounds.
+ virtual bool HasHitTestMask() const;
+
+ // Called by HitTest to retrieve a mask for hit-testing against. Subclasses
+ // override to provide custom shaped hit test regions.
+ virtual void GetHitTestMask(gfx::Path* mask) const;
+
+ // Focus ---------------------------------------------------------------------
+
+ // Returns whether this view can accept focus.
+ // A view can accept focus if it's enabled, focusable and visible.
+ // This method is intended for views to use when calculating preferred size.
+ // The FocusManager and other places use IsFocusableInRootView.
+ virtual bool IsFocusable() const;
+
+ // Override to be notified when focus has changed either to or from this View.
+ virtual void OnFocus();
+ virtual void OnBlur();
+
+ // Handle view focus/blur events for this view.
+ void Focus();
+ void Blur();
+
+ // System events -------------------------------------------------------------
+
+ // Called when the UI theme has changed, overriding allows individual Views to
+ // do special cleanup and processing (such as dropping resource caches).
+ // To dispatch a theme changed notification, call Widget::ThemeChanged().
+ virtual void OnThemeChanged() {}
+
+ // Called when the locale has changed, overriding allows individual Views to
+ // update locale-dependent strings.
+ // To dispatch a locale changed notification, call Widget::LocaleChanged().
+ virtual void OnLocaleChanged() {}
+
+ // Tooltips ------------------------------------------------------------------
+
+ // Views must invoke this when the tooltip text they are to display changes.
+ void TooltipTextChanged();
+
+ // Context menus -------------------------------------------------------------
+
+ // Returns the location, in screen coordinates, to show the context menu at
+ // when the context menu is shown from the keyboard. This implementation
+ // returns the middle of the visible region of this view.
+ //
+ // This method is invoked when the context menu is shown by way of the
+ // keyboard.
+ virtual gfx::Point GetKeyboardContextMenuLocation();
+
+ // Drag and drop -------------------------------------------------------------
+
+ // These are cover methods that invoke the method of the same name on
+ // the DragController. Subclasses may wish to override rather than install
+ // a DragController.
+ // See DragController for a description of these methods.
+ virtual int GetDragOperations(const gfx::Point& press_pt);
+ virtual void WriteDragData(const gfx::Point& press_pt, OSExchangeData* data);
+
+ // Returns whether we're in the middle of a drag session that was initiated
+ // by us.
+ bool InDrag();
+
+ // Returns how much the mouse needs to move in one direction to start a
+ // drag. These methods cache in a platform-appropriate way. These values are
+ // used by the public static method ExceededDragThreshold().
+ static int GetHorizontalDragThreshold();
+ static int GetVerticalDragThreshold();
+
+ // Debugging -----------------------------------------------------------------
+
+#if !defined(NDEBUG)
+ // Returns string containing a graph of the views hierarchy in graphViz DOT
+ // language (http://graphviz.org/). Can be called within debugger and save
+ // to a file to compile/view.
+ // Note: Assumes initial call made with first = true.
+ virtual std::string PrintViewGraph(bool first);
+
+ // Some classes may own an object which contains the children to displayed in
+ // the views hierarchy. The above function gives the class the flexibility to
+ // decide which object should be used to obtain the children, but this
+ // function makes the decision explicit.
+ std::string DoPrintViewGraph(bool first, View* view_with_children);
+#endif
+
+ private:
+ friend class internal::NativeWidgetView;
+ friend class internal::RootView;
+ friend class FocusManager;
+ friend class ViewStorage;
+ friend class Widget;
+ friend class PaintLock;
+
+ // Used to track a drag. RootView passes this into
+ // ProcessMousePressed/Dragged.
+ struct DragInfo {
+ // Sets possible_drag to false and start_x/y to 0. This is invoked by
+ // RootView prior to invoke ProcessMousePressed.
+ void Reset();
+
+ // Sets possible_drag to true and start_pt to the specified point.
+ // This is invoked by the target view if it detects the press may generate
+ // a drag.
+ void PossibleDrag(const gfx::Point& p);
+
+ // Whether the press may generate a drag.
+ bool possible_drag;
+
+ // Coordinates of the mouse press.
+ gfx::Point start_pt;
+ };
+
+ // Painting -----------------------------------------------------------------
+
+ enum SchedulePaintType {
+ // Indicates the size is the same (only the origin changed).
+ SCHEDULE_PAINT_SIZE_SAME,
+
+ // Indicates the size changed (and possibly the origin).
+ SCHEDULE_PAINT_SIZE_CHANGED
+ };
+
+ // Invoked before and after the bounds change to schedule painting the old and
+ // new bounds.
+ void SchedulePaintBoundsChanged(SchedulePaintType type);
+
+ // Common Paint() code shared by accelerated and non-accelerated code paths to
+ // invoke OnPaint() on the View.
+ void PaintCommon(gfx::Canvas* canvas);
+
+ // Tree operations -----------------------------------------------------------
+
+ // Removes |view| from the hierarchy tree. If |update_focus_cycle| is true,
+ // the next and previous focusable views of views pointing to this view are
+ // updated. If |update_tool_tip| is true, the tooltip is updated. If
+ // |delete_removed_view| is true, the view is also deleted (if it is parent
+ // owned).
+ void DoRemoveChildView(View* view,
+ bool update_focus_cycle,
+ bool update_tool_tip,
+ bool delete_removed_view);
+
+ // Call ViewHierarchyChanged for all child views on all parents
+ void PropagateRemoveNotifications(View* parent);
+
+ // Call ViewHierarchyChanged for all children
+ void PropagateAddNotifications(View* parent, View* child);
+
+ // Propagates NativeViewHierarchyChanged() notification through all the
+ // children.
+ void PropagateNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ internal::RootView* root_view);
+
+ // Takes care of registering/unregistering accelerators if
+ // |register_accelerators| true and calls ViewHierarchyChanged().
+ void ViewHierarchyChangedImpl(bool register_accelerators,
+ bool is_add,
+ View* parent,
+ View* child);
+
+ // Size and disposition ------------------------------------------------------
+
+ // Call VisibilityChanged() recursively for all children.
+ void PropagateVisibilityNotifications(View* from, bool is_visible);
+
+ // Registers/unregisters accelerators as necessary and calls
+ // VisibilityChanged().
+ void VisibilityChangedImpl(View* starting_from, bool is_visible);
+
+ // Responsible for propagating bounds change notifications to relevant
+ // views.
+ void BoundsChanged(const gfx::Rect& previous_bounds);
+
+ // Visible bounds notification registration.
+ // When a view is added to a hierarchy, it and all its children are asked if
+ // they need to be registered for "visible bounds within root" notifications
+ // (see comment on OnVisibleBoundsChanged()). If they do, they are registered
+ // with every ancestor between them and the root of the hierarchy.
+ static void RegisterChildrenForVisibleBoundsNotification(View* view);
+ static void UnregisterChildrenForVisibleBoundsNotification(View* view);
+ void RegisterForVisibleBoundsNotification();
+ void UnregisterForVisibleBoundsNotification();
+
+ // Adds/removes view to the list of descendants that are notified any time
+ // this views location and possibly size are changed.
+ void AddDescendantToNotify(View* view);
+ void RemoveDescendantToNotify(View* view);
+
+ // Transformations -----------------------------------------------------------
+
+ // Returns in |transform| the transform to get from coordinates of |ancestor|
+ // to this. Returns true if |ancestor| is found. If |ancestor| is not found,
+ // or NULL, |transform| is set to convert from root view coordinates to this.
+ bool GetTransformRelativeTo(const View* ancestor,
+ ui::Transform* transform) const;
+
+ // Coordinate conversion -----------------------------------------------------
+
+ // Convert a point in the view's coordinate to an ancestor view's coordinate
+ // system using necessary transformations. Returns whether the point was
+ // successfully converted to the ancestor's coordinate system.
+ bool ConvertPointForAncestor(const View* ancestor, gfx::Point* point) const;
+
+ // Convert a point in the ancestor's coordinate system to the view's
+ // coordinate system using necessary transformations. Returns whether the
+ // point was successfully from the ancestor's coordinate system to the view's
+ // coordinate system.
+ bool ConvertPointFromAncestor(const View* ancestor, gfx::Point* point) const;
+
+ // Accelerated painting ------------------------------------------------------
+
+ // Disables painting during time critical operations. Used by PaintLock.
+ // TODO(vollick) Ideally, the widget would not dispatch paints into the
+ // hierarchy during time critical operations and this would not be needed.
+ void set_painting_enabled(bool enabled) { painting_enabled_ = enabled; }
+
+ // Creates the layer and related fields for this view.
+ void CreateLayer();
+
+ // Parents all un-parented layers within this view's hierarchy to this view's
+ // layer.
+ void UpdateParentLayers();
+
+ // Updates the view's layer's parent. Called when a view is added to a view
+ // hierarchy, responsible for parenting the view's layer to the enclosing
+ // layer in the hierarchy.
+ void UpdateParentLayer();
+
+ // Parents this view's layer to |parent_layer|, and sets its bounds and other
+ // properties in accordance to |offset|, the view's offset from the
+ // |parent_layer|.
+ void ReparentLayer(const gfx::Point& offset, ui::Layer* parent_layer);
+
+ // Called to update the layer visibility. The layer will be visible if the
+ // View itself, and all its parent Views are visible. This also updates
+ // visibility of the child layers.
+ void UpdateLayerVisibility();
+ void UpdateChildLayerVisibility(bool visible);
+
+ // Orphans the layers in this subtree that are parented to layers outside of
+ // this subtree.
+ void OrphanLayers();
+
+ // Destroys the layer associated with this view, and reparents any descendants
+ // to the destroyed layer's parent.
+ void DestroyLayer();
+
+ // Input ---------------------------------------------------------------------
+
+ // RootView invokes these. These in turn invoke the appropriate OnMouseXXX
+ // method. If a drag is detected, DoDrag is invoked.
+ bool ProcessMousePressed(const MouseEvent& event, DragInfo* drop_info);
+ bool ProcessMouseDragged(const MouseEvent& event, DragInfo* drop_info);
+ void ProcessMouseReleased(const MouseEvent& event);
+
+ // RootView will invoke this with incoming TouchEvents. Returns the
+ // the result of OnTouchEvent.
+ ui::TouchStatus ProcessTouchEvent(const TouchEvent& event);
+
+ // Accelerators --------------------------------------------------------------
+
+ // Registers this view's keyboard accelerators that are not registered to
+ // FocusManager yet, if possible.
+ void RegisterPendingAccelerators();
+
+ // Unregisters all the keyboard accelerators associated with this view.
+ // |leave_data_intact| if true does not remove data from accelerators_ array,
+ // so it could be re-registered with other focus manager
+ void UnregisterAccelerators(bool leave_data_intact);
+
+ // Focus ---------------------------------------------------------------------
+
+ // Initialize the previous/next focusable views of the specified view relative
+ // to the view at the specified index.
+ void InitFocusSiblings(View* view, int index);
+
+ // System events -------------------------------------------------------------
+
+ // Used to propagate theme changed notifications from the root view to all
+ // views in the hierarchy.
+ virtual void PropagateThemeChanged();
+
+ // Used to propagate locale changed notifications from the root view to all
+ // views in the hierarchy.
+ virtual void PropagateLocaleChanged();
+
+ // Tooltips ------------------------------------------------------------------
+
+ // Propagates UpdateTooltip() to the TooltipManager for the Widget.
+ // This must be invoked any time the View hierarchy changes in such a way
+ // the view under the mouse differs. For example, if the bounds of a View is
+ // changed, this is invoked. Similarly, as Views are added/removed, this
+ // is invoked.
+ void UpdateTooltip();
+
+ // Drag and drop -------------------------------------------------------------
+
+ // Starts a drag and drop operation originating from this view. This invokes
+ // WriteDragData to write the data and GetDragOperations to determine the
+ // supported drag operations. When done, OnDragDone is invoked.
+ void DoDrag(const MouseEvent& event, const gfx::Point& press_pt);
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Creation and lifetime -----------------------------------------------------
+
+ // True if the hierarchy (i.e. the parent View) is responsible for deleting
+ // this View. Default is true.
+ bool parent_owned_;
+
+ // Attributes ----------------------------------------------------------------
+
+ // The id of this View. Used to find this View.
+ int id_;
+
+ // The group of this view. Some view subclasses use this id to find other
+ // views of the same group. For example radio button uses this information
+ // to find other radio buttons.
+ int group_;
+
+ // Tree operations -----------------------------------------------------------
+
+ // This view's parent.
+ View* parent_;
+
+ // This view's children.
+ Views children_;
+
+ // Size and disposition ------------------------------------------------------
+
+ // This View's bounds in the parent coordinate system.
+ gfx::Rect bounds_;
+
+ // Whether this view is visible.
+ bool visible_;
+
+ // Whether this view is enabled.
+ bool enabled_;
+
+ // Whether this view is painting.
+ bool painting_enabled_;
+
+ // Whether or not RegisterViewForVisibleBoundsNotification on the RootView
+ // has been invoked.
+ bool registered_for_visible_bounds_notification_;
+
+ // List of descendants wanting notification when their visible bounds change.
+ scoped_ptr<Views> descendants_to_notify_;
+
+ // Transformations -----------------------------------------------------------
+
+ // Clipping parameters. skia transformation matrix does not give us clipping.
+ // So we do it ourselves.
+ float clip_x_;
+ float clip_y_;
+
+ // Layout --------------------------------------------------------------------
+
+ // Whether the view needs to be laid out.
+ bool needs_layout_;
+
+ // The View's LayoutManager defines the sizing heuristics applied to child
+ // Views. The default is absolute positioning according to bounds_.
+ scoped_ptr<LayoutManager> layout_manager_;
+
+ // Painting ------------------------------------------------------------------
+
+ // Background
+ scoped_ptr<Background> background_;
+
+ // Border.
+ scoped_ptr<Border> border_;
+
+ // RTL painting --------------------------------------------------------------
+
+ // Indicates whether or not the gfx::Canvas object passed to View::Paint()
+ // is going to be flipped horizontally (using the appropriate transform) on
+ // right-to-left locales for this View.
+ bool flip_canvas_on_paint_for_rtl_ui_;
+
+ // Accelerated painting ------------------------------------------------------
+
+ bool paint_to_layer_;
+ scoped_ptr<ui::Layer> layer_;
+
+ // Accelerators --------------------------------------------------------------
+
+ // true if when we were added to hierarchy we were without focus manager
+ // attempt addition when ancestor chain changed.
+ bool accelerator_registration_delayed_;
+
+ // Focus manager accelerators registered on.
+ FocusManager* accelerator_focus_manager_;
+
+ // The list of accelerators. List elements in the range
+ // [0, registered_accelerator_count_) are already registered to FocusManager,
+ // and the rest are not yet.
+ scoped_ptr<std::vector<ui::Accelerator> > accelerators_;
+ size_t registered_accelerator_count_;
+
+ // Focus ---------------------------------------------------------------------
+
+ // Next view to be focused when the Tab key is pressed.
+ View* next_focusable_view_;
+
+ // Next view to be focused when the Shift-Tab key combination is pressed.
+ View* previous_focusable_view_;
+
+ // Whether this view can be focused.
+ bool focusable_;
+
+ // Whether this view is focusable if the user requires full keyboard access,
+ // even though it may not be normally focusable.
+ bool accessibility_focusable_;
+
+ // Context menus -------------------------------------------------------------
+
+ // The menu controller.
+ ContextMenuController* context_menu_controller_;
+
+ // Drag and drop -------------------------------------------------------------
+
+ DragController* drag_controller_;
+
+ // Accessibility -------------------------------------------------------------
+
+ // The Windows-specific accessibility implementation for this view.
+#if defined(OS_WIN)
+ base::win::ScopedComPtr<NativeViewAccessibilityWin>
+ native_view_accessibility_win_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(View);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_VIEW_H_
diff --git a/ui/views/view_aura.cc b/ui/views/view_aura.cc
new file mode 100644
index 0000000..6045b91
--- /dev/null
+++ b/ui/views/view_aura.cc
@@ -0,0 +1,37 @@
+// 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/view.h"
+
+namespace {
+
+// Default horizontal drag threshold in pixels.
+// Same as what gtk uses.
+const int kDefaultHorizontalDragThreshold = 8;
+
+// Default vertical drag threshold in pixels.
+// Same as what gtk uses.
+const int kDefaultVerticalDragThreshold = 8;
+
+} // namespace
+
+namespace views {
+
+gfx::NativeViewAccessible View::GetNativeViewAccessible() {
+ return NULL;
+}
+
+int View::GetHorizontalDragThreshold() {
+ // TODO(jennyz): This value may need to be adjusted for different platforms
+ // and for different display density.
+ return kDefaultHorizontalDragThreshold;
+}
+
+int View::GetVerticalDragThreshold() {
+ // TODO(jennyz): This value may need to be adjusted for different platforms
+ // and for different display density.
+ return kDefaultVerticalDragThreshold;
+}
+
+} // namespace views
diff --git a/ui/views/view_gtk.cc b/ui/views/view_gtk.cc
new file mode 100644
index 0000000..459cd31
--- /dev/null
+++ b/ui/views/view_gtk.cc
@@ -0,0 +1,39 @@
+// 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/view.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+
+namespace views {
+
+gfx::NativeViewAccessible View::GetNativeViewAccessible() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+int View::GetHorizontalDragThreshold() {
+ static bool determined_threshold = false;
+ static int drag_threshold = 8;
+ if (determined_threshold)
+ return drag_threshold;
+ determined_threshold = true;
+ GtkSettings* settings = gtk_settings_get_default();
+ if (!settings)
+ return drag_threshold;
+ int value = 0;
+ g_object_get(G_OBJECT(settings), "gtk-dnd-drag-threshold", &value, NULL);
+ if (value)
+ drag_threshold = value;
+ return drag_threshold;
+}
+
+int View::GetVerticalDragThreshold() {
+ // Vertical and horizontal drag threshold are the same in Gtk.
+ return GetHorizontalDragThreshold();
+}
+
+} // namespace views
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
new file mode 100644
index 0000000..e64fae6
--- /dev/null
+++ b/ui/views/view_unittest.cc
@@ -0,0 +1,3068 @@
+// 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 <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/rand_util.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/compositor/compositor.h"
+#include "ui/gfx/compositor/layer.h"
+#include "ui/gfx/compositor/layer_animator.h"
+#include "ui/gfx/compositor/test/test_compositor.h"
+#include "ui/gfx/compositor/test/test_texture.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/transform.h"
+#include "ui/views/controls/button/button_dropdown.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/native/native_view_host.h"
+#include "ui/views/controls/scroll_view.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/events/event.h"
+#include "ui/views/focus/accelerator_handler.h"
+#include "ui/views/focus/view_storage.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/touchui/gesture_manager.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/native_widget.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/window/dialog_delegate.h"
+#include "views/background.h"
+#include "views/views_delegate.h"
+
+#if defined(OS_WIN)
+#include "ui/views/test/test_views_delegate.h"
+#endif
+#if defined(USE_AURA)
+#include "ui/aura/desktop.h"
+#endif
+
+using ::testing::_;
+
+namespace {
+
+// Returns true if |ancestor| is an ancestor of |layer|.
+bool LayerIsAncestor(const ui::Layer* ancestor, const ui::Layer* layer) {
+ while (layer && layer != ancestor)
+ layer = layer->parent();
+ return layer == ancestor;
+}
+
+// Convenience functions for walking a View tree.
+const views::View* FirstView(const views::View* view) {
+ const views::View* v = view;
+ while (v->has_children())
+ v = v->child_at(0);
+ return v;
+}
+
+const views::View* NextView(const views::View* view) {
+ const views::View* v = view;
+ const views::View* parent = v->parent();
+ if (!parent)
+ return NULL;
+ int next = parent->GetIndexOf(v) + 1;
+ if (next != parent->child_count())
+ return FirstView(parent->child_at(next));
+ return parent;
+}
+
+// Convenience functions for walking a Layer tree.
+const ui::Layer* FirstLayer(const ui::Layer* layer) {
+ const ui::Layer* l = layer;
+ while (l->children().size() > 0)
+ l = l->children()[0];
+ return l;
+}
+
+const ui::Layer* NextLayer(const ui::Layer* layer) {
+ const ui::Layer* parent = layer->parent();
+ if (!parent)
+ return NULL;
+ const std::vector<ui::Layer*> children = parent->children();
+ size_t index;
+ for (index = 0; index < children.size(); index++) {
+ if (children[index] == layer)
+ break;
+ }
+ size_t next = index + 1;
+ if (next < children.size())
+ return FirstLayer(children[next]);
+ return parent;
+}
+
+// Given the root nodes of a View tree and a Layer tree, makes sure the two
+// trees are in sync.
+bool ViewAndLayerTreeAreConsistent(const views::View* view,
+ const ui::Layer* layer) {
+ const views::View* v = FirstView(view);
+ const ui::Layer* l = FirstLayer(layer);
+ while (v && l) {
+ // Find the view with a layer.
+ while (v && !v->layer())
+ v = NextView(v);
+ EXPECT_TRUE(v);
+ if (!v)
+ return false;
+
+ // Check if the View tree and the Layer tree are in sync.
+ EXPECT_EQ(l, v->layer());
+ if (v->layer() != l)
+ return false;
+
+ // Check if the visibility states of the View and the Layer are in sync.
+ EXPECT_EQ(l->IsDrawn(), v->IsVisibleInRootView());
+ if (v->IsVisibleInRootView() != l->IsDrawn()) {
+ for (const views::View* vv = v; vv; vv = vv->parent())
+ LOG(ERROR) << "V: " << vv << " " << vv->IsVisible() << " "
+ << vv->IsVisibleInRootView() << " " << vv->layer();
+ for (const ui::Layer* ll = l; ll; ll = ll->parent())
+ LOG(ERROR) << "L: " << ll << " " << ll->IsDrawn();
+ return false;
+ }
+
+ // Check if the size of the View and the Layer are in sync.
+ EXPECT_EQ(l->bounds(), v->bounds());
+ if (v->bounds() != l->bounds())
+ return false;
+
+ if (v == view || l == layer)
+ return v == view && l == layer;
+
+ v = NextView(v);
+ l = NextLayer(l);
+ }
+
+ return false;
+}
+
+// Constructs a View tree with the specified depth.
+void ConstructTree(views::View* view, int depth) {
+ if (depth == 0)
+ return;
+ int count = base::RandInt(1, 5);
+ for (int i = 0; i < count; i++) {
+ views::View* v = new views::View;
+ view->AddChildView(v);
+ if (base::RandDouble() > 0.5)
+ v->SetPaintToLayer(true);
+ if (base::RandDouble() < 0.2)
+ v->SetVisible(false);
+
+ ConstructTree(v, depth - 1);
+ }
+}
+
+void ScrambleTree(views::View* view) {
+ int count = view->child_count();
+ if (count == 0)
+ return;
+ for (int i = 0; i < count; i++) {
+ ScrambleTree(view->child_at(i));
+ }
+
+ if (count > 1) {
+ int a = base::RandInt(0, count - 1);
+ int b = base::RandInt(0, count - 1);
+
+ views::View* view_a = view->child_at(a);
+ views::View* view_b = view->child_at(b);
+ view->ReorderChildView(view_a, b);
+ view->ReorderChildView(view_b, a);
+ }
+
+ if (!view->layer() && base::RandDouble() < 0.1)
+ view->SetPaintToLayer(true);
+
+ if (base::RandDouble() < 0.1)
+ view->SetVisible(!view->IsVisible());
+}
+
+}
+
+namespace views {
+
+typedef ViewsTestBase ViewTest;
+
+// A derived class for testing purpose.
+class TestView : public View {
+ public:
+ TestView() : View(), in_touch_sequence_(false) {}
+ virtual ~TestView() {}
+
+ // Reset all test state
+ void Reset() {
+ did_change_bounds_ = false;
+ last_mouse_event_type_ = 0;
+ location_.SetPoint(0, 0);
+ last_touch_event_type_ = 0;
+ last_touch_event_was_handled_ = false;
+ last_clip_.setEmpty();
+ accelerator_count_map_.clear();
+ }
+
+ virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
+ virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE;
+ virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE;
+ virtual ui::TouchStatus OnTouchEvent(const TouchEvent& event) OVERRIDE;
+ virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
+ virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
+
+ // OnBoundsChanged.
+ bool did_change_bounds_;
+ gfx::Rect new_bounds_;
+
+ // MouseEvent.
+ int last_mouse_event_type_;
+ gfx::Point location_;
+
+ // Painting.
+ std::vector<gfx::Rect> scheduled_paint_rects_;
+
+ // TouchEvent.
+ int last_touch_event_type_;
+ bool last_touch_event_was_handled_;
+ bool in_touch_sequence_;
+
+ // Painting.
+ SkRect last_clip_;
+
+ // Accelerators.
+ std::map<ui::Accelerator, int> accelerator_count_map_;
+};
+
+// Mock instance of the GestureManager for testing.
+class MockGestureManager : public GestureManager {
+ public:
+ // Reset all test state.
+ void Reset() {
+ last_touch_event_ = 0;
+ last_view_ = NULL;
+ previously_handled_flag_ = false;
+ dispatched_synthetic_event_ = false;
+ }
+
+ bool ProcessTouchEventForGesture(const TouchEvent& event,
+ View* source,
+ ui::TouchStatus status);
+ MockGestureManager();
+
+ bool previously_handled_flag_;
+ int last_touch_event_;
+ View *last_view_;
+ bool dispatched_synthetic_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockGestureManager);
+};
+
+// A view subclass that ignores all touch events for testing purposes.
+class TestViewIgnoreTouch : public TestView {
+ public:
+ TestViewIgnoreTouch() : TestView() {}
+ virtual ~TestViewIgnoreTouch() {}
+
+ private:
+ virtual ui::TouchStatus OnTouchEvent(const TouchEvent& event) OVERRIDE;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// OnBoundsChanged
+////////////////////////////////////////////////////////////////////////////////
+
+void TestView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ did_change_bounds_ = true;
+ new_bounds_ = bounds();
+}
+
+TEST_F(ViewTest, OnBoundsChanged) {
+ TestView v;
+
+ gfx::Rect prev_rect(0, 0, 200, 200);
+ gfx::Rect new_rect(100, 100, 250, 250);
+
+ v.SetBoundsRect(prev_rect);
+ v.Reset();
+ v.SetBoundsRect(new_rect);
+
+ EXPECT_EQ(v.did_change_bounds_, true);
+ EXPECT_EQ(v.new_bounds_, new_rect);
+ EXPECT_EQ(v.bounds(), new_rect);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// MouseEvent
+////////////////////////////////////////////////////////////////////////////////
+
+bool TestView::OnMousePressed(const MouseEvent& event) {
+ last_mouse_event_type_ = event.type();
+ location_.SetPoint(event.x(), event.y());
+ return true;
+}
+
+bool TestView::OnMouseDragged(const MouseEvent& event) {
+ last_mouse_event_type_ = event.type();
+ location_.SetPoint(event.x(), event.y());
+ return true;
+}
+
+void TestView::OnMouseReleased(const MouseEvent& event) {
+ last_mouse_event_type_ = event.type();
+ location_.SetPoint(event.x(), event.y());
+}
+
+TEST_F(ViewTest, MouseEvent) {
+ TestView* v1 = new TestView();
+ v1->SetBounds(0, 0, 300, 300);
+
+ TestView* v2 = new TestView();
+ v2->SetBounds(100, 100, 100, 100);
+
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget->Init(params);
+ View* root = widget->GetRootView();
+
+ root->AddChildView(v1);
+ v1->AddChildView(v2);
+
+ v1->Reset();
+ v2->Reset();
+
+ MouseEvent pressed(ui::ET_MOUSE_PRESSED,
+ 110,
+ 120,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(pressed);
+ EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_PRESSED);
+ EXPECT_EQ(v2->location_.x(), 10);
+ EXPECT_EQ(v2->location_.y(), 20);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_mouse_event_type_, 0);
+
+ // Drag event out of bounds. Should still go to v2
+ v1->Reset();
+ v2->Reset();
+ MouseEvent dragged(ui::ET_MOUSE_DRAGGED,
+ 50,
+ 40,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMouseDragged(dragged);
+ EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_DRAGGED);
+ EXPECT_EQ(v2->location_.x(), -50);
+ EXPECT_EQ(v2->location_.y(), -60);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_mouse_event_type_, 0);
+
+ // Releasted event out of bounds. Should still go to v2
+ v1->Reset();
+ v2->Reset();
+ MouseEvent released(ui::ET_MOUSE_RELEASED, 0, 0, 0);
+ root->OnMouseDragged(released);
+ EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_RELEASED);
+ EXPECT_EQ(v2->location_.x(), -100);
+ EXPECT_EQ(v2->location_.y(), -100);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_mouse_event_type_, 0);
+
+ widget->CloseNow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TouchEvent
+////////////////////////////////////////////////////////////////////////////////
+bool MockGestureManager::ProcessTouchEventForGesture(
+ const TouchEvent& event,
+ View* source,
+ ui::TouchStatus status) {
+ if (status != ui::TOUCH_STATUS_UNKNOWN) {
+ dispatched_synthetic_event_ = false;
+ return false;
+ }
+ last_touch_event_ = event.type();
+ last_view_ = source;
+ previously_handled_flag_ = status != ui::TOUCH_STATUS_UNKNOWN;
+ dispatched_synthetic_event_ = true;
+ return true;
+}
+
+MockGestureManager::MockGestureManager() {
+}
+
+ui::TouchStatus TestView::OnTouchEvent(const TouchEvent& event) {
+ last_touch_event_type_ = event.type();
+ location_.SetPoint(event.x(), event.y());
+ if (!in_touch_sequence_) {
+ if (event.type() == ui::ET_TOUCH_PRESSED) {
+ in_touch_sequence_ = true;
+ return ui::TOUCH_STATUS_START;
+ }
+ } else {
+ if (event.type() == ui::ET_TOUCH_RELEASED) {
+ in_touch_sequence_ = false;
+ return ui::TOUCH_STATUS_END;
+ }
+ return ui::TOUCH_STATUS_CONTINUE;
+ }
+ return last_touch_event_was_handled_ ? ui::TOUCH_STATUS_CONTINUE :
+ ui::TOUCH_STATUS_UNKNOWN;
+}
+
+ui::TouchStatus TestViewIgnoreTouch::OnTouchEvent(const TouchEvent& event) {
+ return ui::TOUCH_STATUS_UNKNOWN;
+}
+
+TEST_F(ViewTest, TouchEvent) {
+ MockGestureManager gm;
+
+ TestView* v1 = new TestView();
+ v1->SetBounds(0, 0, 300, 300);
+
+ TestView* v2 = new TestView();
+ v2->SetBounds(100, 100, 100, 100);
+
+ TestView* v3 = new TestViewIgnoreTouch();
+ v3->SetBounds(0, 0, 100, 100);
+
+ scoped_ptr<Widget> widget(new Widget());
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget->Init(params);
+ View* root = widget->GetRootView();
+
+ root->AddChildView(v1);
+ static_cast<internal::RootView*>(root)->SetGestureManagerForTesting(&gm);
+ v1->AddChildView(v2);
+ v2->AddChildView(v3);
+
+ // |v3| completely obscures |v2|, but all the touch events on |v3| should
+ // reach |v2| because |v3| doesn't process any touch events.
+
+ // Make sure if none of the views handle the touch event, the gesture manager
+ // does.
+ v1->Reset();
+ v2->Reset();
+ gm.Reset();
+
+ TouchEvent unhandled(ui::ET_TOUCH_MOVED,
+ 400,
+ 400,
+ 0, /* no flags */
+ 0, /* first finger touch */
+ 1.0, 0.0, 1.0, 0.0);
+ root->OnTouchEvent(unhandled);
+
+ EXPECT_EQ(v1->last_touch_event_type_, 0);
+ EXPECT_EQ(v2->last_touch_event_type_, 0);
+
+ EXPECT_EQ(gm.previously_handled_flag_, false);
+ EXPECT_EQ(gm.last_touch_event_, ui::ET_TOUCH_MOVED);
+ EXPECT_EQ(gm.last_view_, root);
+ EXPECT_EQ(gm.dispatched_synthetic_event_, true);
+
+ // Test press, drag, release touch sequence.
+ v1->Reset();
+ v2->Reset();
+ gm.Reset();
+
+ TouchEvent pressed(ui::ET_TOUCH_PRESSED,
+ 110,
+ 120,
+ 0, /* no flags */
+ 0, /* first finger touch */
+ 1.0, 0.0, 1.0, 0.0);
+ v2->last_touch_event_was_handled_ = true;
+ root->OnTouchEvent(pressed);
+
+ EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_PRESSED);
+ EXPECT_EQ(v2->location_.x(), 10);
+ EXPECT_EQ(v2->location_.y(), 20);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_touch_event_type_, 0);
+
+ // Since v2 handled the touch-event, the gesture manager should not handle it.
+ EXPECT_EQ(gm.last_touch_event_, 0);
+ EXPECT_EQ(NULL, gm.last_view_);
+ EXPECT_EQ(gm.previously_handled_flag_, false);
+
+ // Drag event out of bounds. Should still go to v2
+ v1->Reset();
+ v2->Reset();
+ TouchEvent dragged(ui::ET_TOUCH_MOVED,
+ 50,
+ 40,
+ 0, /* no flags */
+ 0, /* first finger touch */
+ 1.0, 0.0, 1.0, 0.0);
+
+ root->OnTouchEvent(dragged);
+ EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_MOVED);
+ EXPECT_EQ(v2->location_.x(), -50);
+ EXPECT_EQ(v2->location_.y(), -60);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_touch_event_type_, 0);
+
+ EXPECT_EQ(gm.last_touch_event_, 0);
+ EXPECT_EQ(NULL, gm.last_view_);
+ EXPECT_EQ(gm.previously_handled_flag_, false);
+
+ // Released event out of bounds. Should still go to v2
+ v1->Reset();
+ v2->Reset();
+ TouchEvent released(ui::ET_TOUCH_RELEASED, 0, 0, 0, 0 /* first finger */,
+ 1.0, 0.0, 1.0, 0.0);
+ v2->last_touch_event_was_handled_ = true;
+ root->OnTouchEvent(released);
+ EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_RELEASED);
+ EXPECT_EQ(v2->location_.x(), -100);
+ EXPECT_EQ(v2->location_.y(), -100);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_touch_event_type_, 0);
+
+ EXPECT_EQ(gm.last_touch_event_, 0);
+ EXPECT_EQ(NULL, gm.last_view_);
+ EXPECT_EQ(gm.previously_handled_flag_, false);
+
+ widget->CloseNow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Painting
+////////////////////////////////////////////////////////////////////////////////
+
+void TestView::Paint(gfx::Canvas* canvas) {
+ canvas->GetSkCanvas()->getClipBounds(&last_clip_);
+}
+
+void TestView::SchedulePaintInRect(const gfx::Rect& rect) {
+ scheduled_paint_rects_.push_back(rect);
+ View::SchedulePaintInRect(rect);
+}
+
+void CheckRect(const SkRect& check_rect, const SkRect& target_rect) {
+ EXPECT_EQ(target_rect.fLeft, check_rect.fLeft);
+ EXPECT_EQ(target_rect.fRight, check_rect.fRight);
+ EXPECT_EQ(target_rect.fTop, check_rect.fTop);
+ EXPECT_EQ(target_rect.fBottom, check_rect.fBottom);
+}
+
+/* This test is disabled because it is flakey on some systems.
+TEST_F(ViewTest, DISABLED_Painting) {
+ // Determine if InvalidateRect generates an empty paint rectangle.
+ EmptyWindow paint_window(CRect(50, 50, 650, 650));
+ paint_window.RedrawWindow(CRect(0, 0, 600, 600), NULL,
+ RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
+ bool empty_paint = paint_window.empty_paint();
+
+ NativeWidgetWin window;
+ window.set_delete_on_destroy(false);
+ window.set_window_style(WS_OVERLAPPEDWINDOW);
+ window.Init(NULL, gfx::Rect(50, 50, 650, 650), NULL);
+ View* root = window.GetRootView();
+
+ TestView* v1 = new TestView();
+ v1->SetBounds(0, 0, 650, 650);
+ root->AddChildView(v1);
+
+ TestView* v2 = new TestView();
+ v2->SetBounds(10, 10, 80, 80);
+ v1->AddChildView(v2);
+
+ TestView* v3 = new TestView();
+ v3->SetBounds(10, 10, 60, 60);
+ v2->AddChildView(v3);
+
+ TestView* v4 = new TestView();
+ v4->SetBounds(10, 200, 100, 100);
+ v1->AddChildView(v4);
+
+ // Make sure to paint current rects
+ PaintRootView(root, empty_paint);
+
+
+ v1->Reset();
+ v2->Reset();
+ v3->Reset();
+ v4->Reset();
+ v3->SchedulePaintInRect(gfx::Rect(10, 10, 10, 10));
+ PaintRootView(root, empty_paint);
+
+ SkRect tmp_rect;
+
+ tmp_rect.set(SkIntToScalar(10),
+ SkIntToScalar(10),
+ SkIntToScalar(20),
+ SkIntToScalar(20));
+ CheckRect(v3->last_clip_, tmp_rect);
+
+ tmp_rect.set(SkIntToScalar(20),
+ SkIntToScalar(20),
+ SkIntToScalar(30),
+ SkIntToScalar(30));
+ CheckRect(v2->last_clip_, tmp_rect);
+
+ tmp_rect.set(SkIntToScalar(30),
+ SkIntToScalar(30),
+ SkIntToScalar(40),
+ SkIntToScalar(40));
+ CheckRect(v1->last_clip_, tmp_rect);
+
+ // Make sure v4 was not painted
+ tmp_rect.setEmpty();
+ CheckRect(v4->last_clip_, tmp_rect);
+
+ window.DestroyWindow();
+}
+*/
+
+#if defined(OS_WIN)
+TEST_F(ViewTest, RemoveNotification) {
+#else
+// TODO(beng): stopped working with widget hierarchy split,
+// http://crbug.com/82364
+TEST_F(ViewTest, DISABLED_RemoveNotification) {
+#endif
+ ViewStorage* vs = ViewStorage::GetInstance();
+ Widget* widget = new Widget;
+ widget->Init(Widget::InitParams(Widget::InitParams::TYPE_POPUP));
+ View* root_view = widget->GetRootView();
+
+ View* v1 = new View;
+ int s1 = vs->CreateStorageID();
+ vs->StoreView(s1, v1);
+ root_view->AddChildView(v1);
+ View* v11 = new View;
+ int s11 = vs->CreateStorageID();
+ vs->StoreView(s11, v11);
+ v1->AddChildView(v11);
+ View* v111 = new View;
+ int s111 = vs->CreateStorageID();
+ vs->StoreView(s111, v111);
+ v11->AddChildView(v111);
+ View* v112 = new View;
+ int s112 = vs->CreateStorageID();
+ vs->StoreView(s112, v112);
+ v11->AddChildView(v112);
+ View* v113 = new View;
+ int s113 = vs->CreateStorageID();
+ vs->StoreView(s113, v113);
+ v11->AddChildView(v113);
+ View* v1131 = new View;
+ int s1131 = vs->CreateStorageID();
+ vs->StoreView(s1131, v1131);
+ v113->AddChildView(v1131);
+ View* v12 = new View;
+ int s12 = vs->CreateStorageID();
+ vs->StoreView(s12, v12);
+ v1->AddChildView(v12);
+
+ View* v2 = new View;
+ int s2 = vs->CreateStorageID();
+ vs->StoreView(s2, v2);
+ root_view->AddChildView(v2);
+ View* v21 = new View;
+ int s21 = vs->CreateStorageID();
+ vs->StoreView(s21, v21);
+ v2->AddChildView(v21);
+ View* v211 = new View;
+ int s211 = vs->CreateStorageID();
+ vs->StoreView(s211, v211);
+ v21->AddChildView(v211);
+
+ size_t stored_views = vs->view_count();
+
+ // Try removing a leaf view.
+ v21->RemoveChildView(v211);
+ EXPECT_EQ(stored_views - 1, vs->view_count());
+ EXPECT_EQ(NULL, vs->RetrieveView(s211));
+ delete v211; // We won't use this one anymore.
+
+ // Now try removing a view with a hierarchy of depth 1.
+ v11->RemoveChildView(v113);
+ EXPECT_EQ(stored_views - 3, vs->view_count());
+ EXPECT_EQ(NULL, vs->RetrieveView(s113));
+ EXPECT_EQ(NULL, vs->RetrieveView(s1131));
+ delete v113; // We won't use this one anymore.
+
+ // Now remove even more.
+ root_view->RemoveChildView(v1);
+ EXPECT_EQ(NULL, vs->RetrieveView(s1));
+ EXPECT_EQ(NULL, vs->RetrieveView(s11));
+ EXPECT_EQ(NULL, vs->RetrieveView(s12));
+ EXPECT_EQ(NULL, vs->RetrieveView(s111));
+ EXPECT_EQ(NULL, vs->RetrieveView(s112));
+
+ // Put v1 back for more tests.
+ root_view->AddChildView(v1);
+ vs->StoreView(s1, v1);
+
+ // Synchronously closing the window deletes the view hierarchy, which should
+ // remove all its views from ViewStorage.
+ widget->CloseNow();
+ EXPECT_EQ(stored_views - 10, vs->view_count());
+ EXPECT_EQ(NULL, vs->RetrieveView(s1));
+ EXPECT_EQ(NULL, vs->RetrieveView(s12));
+ EXPECT_EQ(NULL, vs->RetrieveView(s11));
+ EXPECT_EQ(NULL, vs->RetrieveView(s12));
+ EXPECT_EQ(NULL, vs->RetrieveView(s21));
+ EXPECT_EQ(NULL, vs->RetrieveView(s111));
+ EXPECT_EQ(NULL, vs->RetrieveView(s112));
+}
+
+namespace {
+class HitTestView : public View {
+ public:
+ explicit HitTestView(bool has_hittest_mask)
+ : has_hittest_mask_(has_hittest_mask) {
+ }
+ virtual ~HitTestView() {}
+
+ protected:
+ // Overridden from View:
+ virtual bool HasHitTestMask() const {
+ return has_hittest_mask_;
+ }
+ virtual void GetHitTestMask(gfx::Path* mask) const {
+ DCHECK(has_hittest_mask_);
+ DCHECK(mask);
+
+ SkScalar w = SkIntToScalar(width());
+ SkScalar h = SkIntToScalar(height());
+
+ // Create a triangular mask within the bounds of this View.
+ mask->moveTo(w / 2, 0);
+ mask->lineTo(w, h);
+ mask->lineTo(0, h);
+ mask->close();
+ }
+
+ private:
+ bool has_hittest_mask_;
+
+ DISALLOW_COPY_AND_ASSIGN(HitTestView);
+};
+
+gfx::Point ConvertPointToView(View* view, const gfx::Point& p) {
+ gfx::Point tmp(p);
+ View::ConvertPointToView(view->GetWidget()->GetRootView(), view, &tmp);
+ return tmp;
+}
+
+void RotateCounterclockwise(ui::Transform& transform) {
+ transform.matrix().set3x3(0, -1, 0,
+ 1, 0, 0,
+ 0, 0, 1);
+}
+
+void RotateClockwise(ui::Transform& transform) {
+ transform.matrix().set3x3( 0, 1, 0,
+ -1, 0, 0,
+ 0, 0, 1);
+}
+
+} // namespace
+
+TEST_F(ViewTest, HitTestMasks) {
+ Widget* widget = new Widget;
+ widget->Init(Widget::InitParams(Widget::InitParams::TYPE_POPUP));
+ View* root_view = widget->GetRootView();
+ root_view->SetBounds(0, 0, 500, 500);
+
+ gfx::Rect v1_bounds = gfx::Rect(0, 0, 100, 100);
+ HitTestView* v1 = new HitTestView(false);
+ v1->SetBoundsRect(v1_bounds);
+ root_view->AddChildView(v1);
+
+ gfx::Rect v2_bounds = gfx::Rect(105, 0, 100, 100);
+ HitTestView* v2 = new HitTestView(true);
+ v2->SetBoundsRect(v2_bounds);
+ root_view->AddChildView(v2);
+
+ gfx::Point v1_centerpoint = v1_bounds.CenterPoint();
+ gfx::Point v2_centerpoint = v2_bounds.CenterPoint();
+ gfx::Point v1_origin = v1_bounds.origin();
+ gfx::Point v2_origin = v2_bounds.origin();
+
+ // Test HitTest
+ EXPECT_TRUE(v1->HitTest(ConvertPointToView(v1, v1_centerpoint)));
+ EXPECT_TRUE(v2->HitTest(ConvertPointToView(v2, v2_centerpoint)));
+
+ EXPECT_TRUE(v1->HitTest(ConvertPointToView(v1, v1_origin)));
+ EXPECT_FALSE(v2->HitTest(ConvertPointToView(v2, v2_origin)));
+
+ // Test GetEventHandlerForPoint
+ EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_centerpoint));
+ EXPECT_EQ(v2, root_view->GetEventHandlerForPoint(v2_centerpoint));
+ EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_origin));
+ EXPECT_EQ(root_view, root_view->GetEventHandlerForPoint(v2_origin));
+
+ widget->CloseNow();
+}
+
+TEST_F(ViewTest, Textfield) {
+ const string16 kText = ASCIIToUTF16("Reality is that which, when you stop "
+ "believing it, doesn't go away.");
+ const string16 kExtraText = ASCIIToUTF16("Pretty deep, Philip!");
+ const string16 kEmptyString;
+
+ ui::Clipboard clipboard;
+
+ Widget* widget = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ widget->Init(params);
+ View* root_view = widget->GetRootView();
+
+ Textfield* textfield = new Textfield();
+ root_view->AddChildView(textfield);
+
+ // Test setting, appending text.
+ textfield->SetText(kText);
+ EXPECT_EQ(kText, textfield->text());
+ textfield->AppendText(kExtraText);
+ EXPECT_EQ(kText + kExtraText, textfield->text());
+ textfield->SetText(string16());
+ EXPECT_EQ(kEmptyString, textfield->text());
+
+ // Test selection related methods.
+ textfield->SetText(kText);
+ EXPECT_EQ(kEmptyString, textfield->GetSelectedText());
+ textfield->SelectAll();
+ EXPECT_EQ(kText, textfield->text());
+ textfield->ClearSelection();
+ EXPECT_EQ(kEmptyString, textfield->GetSelectedText());
+
+ widget->CloseNow();
+}
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+
+// Tests that the Textfield view respond appropiately to cut/copy/paste.
+TEST_F(ViewTest, TextfieldCutCopyPaste) {
+ const string16 kNormalText = ASCIIToUTF16("Normal");
+ const string16 kReadOnlyText = ASCIIToUTF16("Read only");
+ const string16 kPasswordText = ASCIIToUTF16("Password! ** Secret stuff **");
+
+ ui::Clipboard clipboard;
+
+ Widget* widget = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ widget->Init(params);
+ View* root_view = widget->GetRootView();
+
+ Textfield* normal = new Textfield();
+ Textfield* read_only = new Textfield();
+ read_only->SetReadOnly(true);
+ Textfield* password = new Textfield(Textfield::STYLE_PASSWORD);
+
+ root_view->AddChildView(normal);
+ root_view->AddChildView(read_only);
+ root_view->AddChildView(password);
+
+ normal->SetText(kNormalText);
+ read_only->SetText(kReadOnlyText);
+ password->SetText(kPasswordText);
+
+ //
+ // Test cut.
+ //
+ ASSERT_TRUE(normal->GetTestingHandle());
+ normal->SelectAll();
+ ::SendMessage(normal->GetTestingHandle(), WM_CUT, 0, 0);
+
+ string16 result;
+ clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
+ EXPECT_EQ(kNormalText, result);
+ normal->SetText(kNormalText); // Let's revert to the original content.
+
+ ASSERT_TRUE(read_only->GetTestingHandle());
+ read_only->SelectAll();
+ ::SendMessage(read_only->GetTestingHandle(), WM_CUT, 0, 0);
+ result.clear();
+ clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
+ // Cut should have failed, so the clipboard content should not have changed.
+ EXPECT_EQ(kNormalText, result);
+
+ ASSERT_TRUE(password->GetTestingHandle());
+ password->SelectAll();
+ ::SendMessage(password->GetTestingHandle(), WM_CUT, 0, 0);
+ result.clear();
+ clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
+ // Cut should have failed, so the clipboard content should not have changed.
+ EXPECT_EQ(kNormalText, result);
+
+ //
+ // Test copy.
+ //
+
+ // Let's start with read_only as the clipboard already contains the content
+ // of normal.
+ read_only->SelectAll();
+ ::SendMessage(read_only->GetTestingHandle(), WM_COPY, 0, 0);
+ result.clear();
+ clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
+ EXPECT_EQ(kReadOnlyText, result);
+
+ normal->SelectAll();
+ ::SendMessage(normal->GetTestingHandle(), WM_COPY, 0, 0);
+ result.clear();
+ clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
+ EXPECT_EQ(kNormalText, result);
+
+ password->SelectAll();
+ ::SendMessage(password->GetTestingHandle(), WM_COPY, 0, 0);
+ result.clear();
+ clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
+ // We don't let you copy from a password field, clipboard should not have
+ // changed.
+ EXPECT_EQ(kNormalText, result);
+
+ //
+ // Test Paste.
+ //
+ // Note that we use GetWindowText instead of Textfield::GetText below as the
+ // text in the Textfield class is synced to the text of the HWND on
+ // WM_KEYDOWN messages that we are not simulating here.
+
+ // Attempting to copy kNormalText in a read-only text-field should fail.
+ read_only->SelectAll();
+ ::SendMessage(read_only->GetTestingHandle(), WM_KEYDOWN, 0, 0);
+ wchar_t buffer[1024] = { 0 };
+ ::GetWindowText(read_only->GetTestingHandle(), buffer, 1024);
+ EXPECT_EQ(kReadOnlyText, string16(buffer));
+
+ password->SelectAll();
+ ::SendMessage(password->GetTestingHandle(), WM_PASTE, 0, 0);
+ ::GetWindowText(password->GetTestingHandle(), buffer, 1024);
+ EXPECT_EQ(kNormalText, string16(buffer));
+
+ // Copy from read_only so the string we are pasting is not the same as the
+ // current one.
+ read_only->SelectAll();
+ ::SendMessage(read_only->GetTestingHandle(), WM_COPY, 0, 0);
+ normal->SelectAll();
+ ::SendMessage(normal->GetTestingHandle(), WM_PASTE, 0, 0);
+ ::GetWindowText(normal->GetTestingHandle(), buffer, 1024);
+ EXPECT_EQ(kReadOnlyText, string16(buffer));
+ widget->CloseNow();
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Accelerators
+////////////////////////////////////////////////////////////////////////////////
+bool TestView::AcceleratorPressed(const ui::Accelerator& accelerator) {
+ accelerator_count_map_[accelerator]++;
+ return true;
+}
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+TEST_F(ViewTest, ActivateAccelerator) {
+ // Register a keyboard accelerator before the view is added to a window.
+ ui::Accelerator return_accelerator(ui::VKEY_RETURN, false, false, false);
+ TestView* view = new TestView();
+ view->Reset();
+ view->AddAccelerator(return_accelerator);
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0);
+
+ // Create a window and add the view as its child.
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ widget->Init(params);
+ View* root = widget->GetRootView();
+ root->AddChildView(view);
+ widget->Show();
+
+ // Get the focus manager.
+ FocusManager* focus_manager = widget->GetFocusManager();
+ ASSERT_TRUE(focus_manager);
+
+ // Hit the return key and see if it takes effect.
+ EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
+
+ // Hit the escape key. Nothing should happen.
+ ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, false, false, false);
+ EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator));
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
+ EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 0);
+
+ // Now register the escape key and hit it again.
+ view->AddAccelerator(escape_accelerator);
+ EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator));
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
+ EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
+
+ // Remove the return key accelerator.
+ view->RemoveAccelerator(return_accelerator);
+ EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
+ EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
+
+ // Add it again. Hit the return key and the escape key.
+ view->AddAccelerator(return_accelerator);
+ EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
+ EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
+ EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator));
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
+ EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
+
+ // Remove all the accelerators.
+ view->ResetAccelerators();
+ EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
+ EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
+ EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator));
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
+ EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
+
+ widget->CloseNow();
+}
+#endif
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+TEST_F(ViewTest, HiddenViewWithAccelerator) {
+ ui::Accelerator return_accelerator(ui::VKEY_RETURN, false, false, false);
+ TestView* view = new TestView();
+ view->Reset();
+ view->AddAccelerator(return_accelerator);
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0);
+
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ widget->Init(params);
+ View* root = widget->GetRootView();
+ root->AddChildView(view);
+ widget->Show();
+
+ FocusManager* focus_manager = widget->GetFocusManager();
+ ASSERT_TRUE(focus_manager);
+
+ view->SetVisible(false);
+ EXPECT_EQ(NULL,
+ focus_manager->GetCurrentTargetForAccelerator(return_accelerator));
+
+ view->SetVisible(true);
+ EXPECT_EQ(view,
+ focus_manager->GetCurrentTargetForAccelerator(return_accelerator));
+
+ widget->CloseNow();
+}
+#endif
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) {
+ ui::Accelerator return_accelerator(ui::VKEY_RETURN, false, false, false);
+ TestView* view = new TestView();
+ view->Reset();
+ view->AddAccelerator(return_accelerator);
+ EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0);
+
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ widget->Init(params);
+ View* root = widget->GetRootView();
+ root->AddChildView(view);
+
+ FocusManager* focus_manager = widget->GetFocusManager();
+ ASSERT_TRUE(focus_manager);
+
+ EXPECT_EQ(NULL,
+ focus_manager->GetCurrentTargetForAccelerator(return_accelerator));
+
+ widget->Show();
+ EXPECT_EQ(view,
+ focus_manager->GetCurrentTargetForAccelerator(return_accelerator));
+
+ widget->Hide();
+ EXPECT_EQ(NULL,
+ focus_manager->GetCurrentTargetForAccelerator(return_accelerator));
+
+ widget->CloseNow();
+}
+#endif
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+////////////////////////////////////////////////////////////////////////////////
+// Mouse-wheel message rerouting
+////////////////////////////////////////////////////////////////////////////////
+class ScrollableTestView : public View {
+ public:
+ ScrollableTestView() { }
+
+ virtual gfx::Size GetPreferredSize() {
+ return gfx::Size(100, 10000);
+ }
+
+ virtual void Layout() {
+ SizeToPreferredSize();
+ }
+};
+
+class TestViewWithControls : public View {
+ public:
+ TestViewWithControls() {
+ text_field_ = new Textfield();
+ AddChildView(text_field_);
+ }
+
+ Textfield* text_field_;
+};
+
+class SimpleWidgetDelegate : public WidgetDelegate {
+ public:
+ explicit SimpleWidgetDelegate(View* contents) : contents_(contents) { }
+
+ virtual void DeleteDelegate() { delete this; }
+
+ virtual View* GetContentsView() { return contents_; }
+
+ virtual Widget* GetWidget() { return contents_->GetWidget(); }
+ virtual const Widget* GetWidget() const { return contents_->GetWidget(); }
+
+ private:
+ View* contents_;
+};
+
+// Tests that the mouse-wheel messages are correctly rerouted to the window
+// under the mouse.
+// TODO(jcampan): http://crbug.com/10572 Disabled as it fails on the Vista build
+// bot.
+// Note that this fails for a variety of reasons:
+// - focused view is apparently reset across window activations and never
+// properly restored
+// - this test depends on you not having any other window visible open under the
+// area that it opens the test windows. --beng
+TEST_F(ViewTest, DISABLED_RerouteMouseWheelTest) {
+ TestViewWithControls* view_with_controls = new TestViewWithControls();
+ Widget* window1 = Widget::CreateWindowWithBounds(
+ new SimpleWidgetDelegate(view_with_controls),
+ gfx::Rect(0, 0, 100, 100));
+ window1->Show();
+ ScrollView* scroll_view = new ScrollView();
+ scroll_view->SetContents(new ScrollableTestView());
+ Widget* window2 = Widget::CreateWindowWithBounds(
+ new SimpleWidgetDelegate(scroll_view),
+ gfx::Rect(200, 200, 100, 100));
+ window2->Show();
+ EXPECT_EQ(0, scroll_view->GetVisibleRect().y());
+
+ // Make the window1 active, as this is what it would be in real-world.
+ window1->Activate();
+
+ // Let's send a mouse-wheel message to the different controls and check that
+ // it is rerouted to the window under the mouse (effectively scrolling the
+ // scroll-view).
+
+ // First to the Window's HWND.
+ ::SendMessage(view_with_controls->GetWidget()->GetNativeView(),
+ WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
+ EXPECT_EQ(20, scroll_view->GetVisibleRect().y());
+
+ // Then the text-field.
+ ::SendMessage(view_with_controls->text_field_->GetTestingHandle(),
+ WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
+ EXPECT_EQ(80, scroll_view->GetVisibleRect().y());
+
+ // Ensure we don't scroll when the mouse is not over that window.
+ ::SendMessage(view_with_controls->text_field_->GetTestingHandle(),
+ WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(50, 50));
+ EXPECT_EQ(80, scroll_view->GetVisibleRect().y());
+
+ window1->CloseNow();
+ window2->CloseNow();
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Dialogs' default button
+////////////////////////////////////////////////////////////////////////////////
+
+class MockMenuModel : public ui::MenuModel {
+ public:
+ MOCK_CONST_METHOD0(HasIcons, bool());
+ MOCK_CONST_METHOD1(GetFirstItemIndex, int(gfx::NativeMenu native_menu));
+ MOCK_CONST_METHOD0(GetItemCount, int());
+ MOCK_CONST_METHOD1(GetTypeAt, ItemType(int index));
+ MOCK_CONST_METHOD1(GetCommandIdAt, int(int index));
+ MOCK_CONST_METHOD1(GetLabelAt, string16(int index));
+ MOCK_CONST_METHOD1(IsItemDynamicAt, bool(int index));
+ MOCK_CONST_METHOD1(GetLabelFontAt, const gfx::Font* (int index));
+ MOCK_CONST_METHOD2(GetAcceleratorAt, bool(int index,
+ ui::Accelerator* accelerator));
+ MOCK_CONST_METHOD1(IsItemCheckedAt, bool(int index));
+ MOCK_CONST_METHOD1(GetGroupIdAt, int(int index));
+ MOCK_METHOD2(GetIconAt, bool(int index, SkBitmap* icon));
+ MOCK_CONST_METHOD1(GetButtonMenuItemAt, ui::ButtonMenuItemModel*(int index));
+ MOCK_CONST_METHOD1(IsEnabledAt, bool(int index));
+ MOCK_CONST_METHOD1(IsVisibleAt, bool(int index));
+ MOCK_CONST_METHOD1(GetSubmenuModelAt, MenuModel*(int index));
+ MOCK_METHOD1(HighlightChangedTo, void(int index));
+ MOCK_METHOD1(ActivatedAt, void(int index));
+ MOCK_METHOD2(ActivatedAt, void(int index, int disposition));
+ MOCK_METHOD0(MenuWillShow, void());
+ MOCK_METHOD0(MenuClosed, void());
+ MOCK_METHOD1(SetMenuModelDelegate, void(ui::MenuModelDelegate* delegate));
+ MOCK_METHOD3(GetModelAndIndexForCommandId, bool(int command_id,
+ MenuModel** model, int* index));
+};
+
+class TestDialog : public DialogDelegate, public ButtonListener {
+ public:
+ explicit TestDialog(MockMenuModel* mock_menu_model)
+ : contents_(NULL),
+ button1_(NULL),
+ button2_(NULL),
+ checkbox_(NULL),
+ button_drop_(NULL),
+ last_pressed_button_(NULL),
+ mock_menu_model_(mock_menu_model),
+ canceled_(false),
+ oked_(false),
+ closeable_(false),
+ widget_(NULL) {
+ }
+
+ void TearDown() {
+ // Now we can close safely.
+ closeable_ = true;
+ widget_->Close();
+ widget_ = NULL;
+ // delegate has to be alive while shutting down.
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ }
+
+ // DialogDelegate implementation:
+ virtual int GetDefaultDialogButton() const OVERRIDE {
+ return ui::DIALOG_BUTTON_OK;
+ }
+
+ virtual View* GetContentsView() OVERRIDE {
+ if (!contents_) {
+ contents_ = new View;
+ button1_ = new NativeTextButton(this, ASCIIToUTF16("Button1"));
+ button2_ = new NativeTextButton(this, ASCIIToUTF16("Button2"));
+ checkbox_ = new Checkbox(ASCIIToUTF16("My checkbox"));
+ button_drop_ = new ButtonDropDown(this, mock_menu_model_);
+ contents_->AddChildView(button1_);
+ contents_->AddChildView(button2_);
+ contents_->AddChildView(checkbox_);
+ contents_->AddChildView(button_drop_);
+ }
+ return contents_;
+ }
+
+ // Prevent the dialog from really closing (so we can click the OK/Cancel
+ // buttons to our heart's content).
+ virtual bool Cancel() OVERRIDE {
+ canceled_ = true;
+ return closeable_;
+ }
+ virtual bool Accept() OVERRIDE {
+ oked_ = true;
+ return closeable_;
+ }
+
+ virtual Widget* GetWidget() OVERRIDE {
+ return widget_;
+ }
+ virtual const Widget* GetWidget() const OVERRIDE {
+ return widget_;
+ }
+
+ // ButtonListener implementation.
+ virtual void ButtonPressed(Button* sender, const Event& event) OVERRIDE {
+ last_pressed_button_ = sender;
+ }
+
+ void ResetStates() {
+ oked_ = false;
+ canceled_ = false;
+ last_pressed_button_ = NULL;
+ }
+
+ // Set up expectations for methods that are called when an (empty) menu is
+ // shown from a drop down button.
+ void ExpectShowDropMenu() {
+ if (mock_menu_model_) {
+ EXPECT_CALL(*mock_menu_model_, HasIcons());
+ EXPECT_CALL(*mock_menu_model_, GetFirstItemIndex(_));
+ EXPECT_CALL(*mock_menu_model_, GetItemCount());
+ EXPECT_CALL(*mock_menu_model_, MenuClosed());
+ }
+ }
+
+ View* contents_;
+ NativeTextButton* button1_;
+ NativeTextButton* button2_;
+ Checkbox* checkbox_;
+ ButtonDropDown* button_drop_;
+ Button* last_pressed_button_;
+ MockMenuModel* mock_menu_model_;
+
+ bool canceled_;
+ bool oked_;
+ bool closeable_;
+ Widget* widget_;
+};
+
+class DefaultButtonTest : public ViewTest {
+ public:
+ enum ButtonID {
+ OK,
+ CANCEL,
+ BUTTON1,
+ BUTTON2
+ };
+
+ DefaultButtonTest()
+ : focus_manager_(NULL),
+ test_dialog_(NULL),
+ client_view_(NULL),
+ ok_button_(NULL),
+ cancel_button_(NULL) {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ ViewTest::SetUp();
+ test_dialog_ = new TestDialog(NULL);
+ Widget* window =
+ Widget::CreateWindowWithBounds(test_dialog_, gfx::Rect(0, 0, 100, 100));
+ test_dialog_->widget_ = window;
+ window->Show();
+ focus_manager_ = test_dialog_->contents_->GetFocusManager();
+ ASSERT_TRUE(focus_manager_ != NULL);
+ client_view_ =
+ static_cast<DialogClientView*>(window->client_view());
+ ok_button_ = client_view_->ok_button();
+ cancel_button_ = client_view_->cancel_button();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ test_dialog_->TearDown();
+ ViewTest::TearDown();
+ }
+
+ void SimulatePressingEnterAndCheckDefaultButton(ButtonID button_id) {
+ KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0);
+ focus_manager_->OnKeyEvent(event);
+ switch (button_id) {
+ case OK:
+ EXPECT_TRUE(test_dialog_->oked_);
+ EXPECT_FALSE(test_dialog_->canceled_);
+ EXPECT_FALSE(test_dialog_->last_pressed_button_);
+ break;
+ case CANCEL:
+ EXPECT_FALSE(test_dialog_->oked_);
+ EXPECT_TRUE(test_dialog_->canceled_);
+ EXPECT_FALSE(test_dialog_->last_pressed_button_);
+ break;
+ case BUTTON1:
+ EXPECT_FALSE(test_dialog_->oked_);
+ EXPECT_FALSE(test_dialog_->canceled_);
+ EXPECT_TRUE(test_dialog_->last_pressed_button_ ==
+ test_dialog_->button1_);
+ break;
+ case BUTTON2:
+ EXPECT_FALSE(test_dialog_->oked_);
+ EXPECT_FALSE(test_dialog_->canceled_);
+ EXPECT_TRUE(test_dialog_->last_pressed_button_ ==
+ test_dialog_->button2_);
+ break;
+ }
+ test_dialog_->ResetStates();
+ }
+
+ FocusManager* focus_manager_;
+ TestDialog* test_dialog_;
+ DialogClientView* client_view_;
+ NativeTextButton* ok_button_;
+ NativeTextButton* cancel_button_;
+};
+
+TEST_F(DefaultButtonTest, DialogDefaultButtonTest) {
+ // Window has just been shown, we expect the default button specified in the
+ // DialogDelegate.
+ EXPECT_TRUE(ok_button_->is_default());
+
+ // Simulate pressing enter, that should trigger the OK button.
+ SimulatePressingEnterAndCheckDefaultButton(OK);
+
+ // Simulate focusing another button, it should become the default button.
+ client_view_->OnWillChangeFocus(ok_button_, test_dialog_->button1_);
+ EXPECT_FALSE(ok_button_->is_default());
+ EXPECT_TRUE(test_dialog_->button1_->is_default());
+ // Simulate pressing enter, that should trigger button1.
+ SimulatePressingEnterAndCheckDefaultButton(BUTTON1);
+
+ // Now select something that is not a button, the OK should become the default
+ // button again.
+ client_view_->OnWillChangeFocus(test_dialog_->button1_,
+ test_dialog_->checkbox_);
+ EXPECT_TRUE(ok_button_->is_default());
+ EXPECT_FALSE(test_dialog_->button1_->is_default());
+ SimulatePressingEnterAndCheckDefaultButton(OK);
+
+ // Select yet another button.
+ client_view_->OnWillChangeFocus(test_dialog_->checkbox_,
+ test_dialog_->button2_);
+ EXPECT_FALSE(ok_button_->is_default());
+ EXPECT_FALSE(test_dialog_->button1_->is_default());
+ EXPECT_TRUE(test_dialog_->button2_->is_default());
+ SimulatePressingEnterAndCheckDefaultButton(BUTTON2);
+
+ // Focus nothing.
+ client_view_->OnWillChangeFocus(test_dialog_->button2_, NULL);
+ EXPECT_TRUE(ok_button_->is_default());
+ EXPECT_FALSE(test_dialog_->button1_->is_default());
+ EXPECT_FALSE(test_dialog_->button2_->is_default());
+ SimulatePressingEnterAndCheckDefaultButton(OK);
+
+ // Focus the cancel button.
+ client_view_->OnWillChangeFocus(NULL, cancel_button_);
+ EXPECT_FALSE(ok_button_->is_default());
+ EXPECT_TRUE(cancel_button_->is_default());
+ EXPECT_FALSE(test_dialog_->button1_->is_default());
+ EXPECT_FALSE(test_dialog_->button2_->is_default());
+ SimulatePressingEnterAndCheckDefaultButton(CANCEL);
+}
+
+class ButtonDropDownTest : public ViewTest {
+ public:
+ ButtonDropDownTest()
+ : test_dialog_(NULL),
+ button_as_view_(NULL) {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ ViewTest::SetUp();
+ test_dialog_ = new TestDialog(&mock_menu_model_);
+ Widget* window =
+ Widget::CreateWindowWithBounds(test_dialog_, gfx::Rect(0, 0, 100, 100));
+ test_dialog_->widget_ = window;
+ window->Show();
+ test_dialog_->button_drop_->SetBounds(0, 0, 100, 100);
+ // We have to cast the button back into a View in order to invoke it's
+ // OnMouseReleased method.
+ button_as_view_ = static_cast<View*>(test_dialog_->button_drop_);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ test_dialog_->TearDown();
+ ViewTest::TearDown();
+ }
+
+ TestDialog* test_dialog_;
+ MockMenuModel mock_menu_model_;
+ // This is owned by test_dialog_.
+ View* button_as_view_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ButtonDropDownTest);
+};
+
+// Ensure that regular clicks on the drop down button still work. (i.e. - the
+// click events are processed and the listener gets the click)
+TEST_F(ButtonDropDownTest, RegularClickTest) {
+ MouseEvent press_event(ui::ET_MOUSE_PRESSED, 1, 1, ui::EF_LEFT_BUTTON_DOWN);
+ MouseEvent release_event(ui::ET_MOUSE_RELEASED, 1, 1,
+ ui::EF_LEFT_BUTTON_DOWN);
+ button_as_view_->OnMousePressed(press_event);
+ button_as_view_->OnMouseReleased(release_event);
+ EXPECT_EQ(test_dialog_->last_pressed_button_, test_dialog_->button_drop_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// View hierarchy / Visibility changes
+////////////////////////////////////////////////////////////////////////////////
+/*
+TEST_F(ViewTest, ChangeVisibility) {
+#if defined(OS_LINUX)
+ // Make CRITICAL messages fatal
+ // TODO(oshima): we probably should enable this for entire tests on linux.
+ g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL);
+#endif
+ scoped_ptr<Widget> window(CreateWidget());
+ window->Init(NULL, gfx::Rect(0, 0, 500, 300));
+ View* root_view = window->GetRootView();
+ NativeTextButton* native = new NativeTextButton(NULL, ASCIIToUTF16("Native"));
+
+ root_view->SetContentsView(native);
+ native->SetVisible(true);
+
+ root_view->RemoveChildView(native);
+ native->SetVisible(false);
+ // Change visibility to true with no widget.
+ native->SetVisible(true);
+
+ root_view->SetContentsView(native);
+ native->SetVisible(true);
+}
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Native view hierachy
+////////////////////////////////////////////////////////////////////////////////
+class TestNativeViewHierarchy : public View {
+ public:
+ TestNativeViewHierarchy() {
+ }
+
+ virtual void NativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ internal::RootView* root_view) {
+ NotificationInfo info;
+ info.attached = attached;
+ info.native_view = native_view;
+ info.root_view = root_view;
+ notifications_.push_back(info);
+ };
+ struct NotificationInfo {
+ bool attached;
+ gfx::NativeView native_view;
+ internal::RootView* root_view;
+ };
+ static const size_t kTotalViews = 2;
+ std::vector<NotificationInfo> notifications_;
+};
+
+class TestChangeNativeViewHierarchy {
+ public:
+ explicit TestChangeNativeViewHierarchy(ViewTest *view_test) {
+ view_test_ = view_test;
+ native_host_ = new NativeViewHost();
+ host_ = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(0, 0, 500, 300);
+ host_->Init(params);
+ host_->GetRootView()->AddChildView(native_host_);
+ for (size_t i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
+ windows_[i] = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
+ params.parent = host_->GetNativeView();
+ params.bounds = gfx::Rect(0, 0, 500, 300);
+ windows_[i]->Init(params);
+ root_views_[i] = windows_[i]->GetRootView();
+ test_views_[i] = new TestNativeViewHierarchy;
+ root_views_[i]->AddChildView(test_views_[i]);
+ }
+ }
+
+ ~TestChangeNativeViewHierarchy() {
+ for (size_t i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
+ windows_[i]->Close();
+ }
+ host_->Close();
+ // Will close and self-delete widgets - no need to manually delete them.
+ view_test_->RunPendingMessages();
+ }
+
+ void CheckEnumeratingNativeWidgets() {
+ if (!host_->GetTopLevelWidget())
+ return;
+ Widget::Widgets widgets;
+ Widget::GetAllChildWidgets(host_->GetNativeView(), &widgets);
+ EXPECT_EQ(TestNativeViewHierarchy::kTotalViews + 1, widgets.size());
+ // Unfortunately there is no guarantee the sequence of views here so always
+ // go through all of them.
+ for (Widget::Widgets::iterator i = widgets.begin();
+ i != widgets.end(); ++i) {
+ View* root_view = (*i)->GetRootView();
+ if (host_->GetRootView() == root_view)
+ continue;
+ size_t j;
+ for (j = 0; j < TestNativeViewHierarchy::kTotalViews; ++j)
+ if (root_views_[j] == root_view)
+ break;
+ // EXPECT_LT/GT/GE() fails to compile with class-defined constants
+ // with gcc, with error
+ // "error: undefined reference to 'TestNativeViewHierarchy::kTotalViews'"
+ // so I forced to use EXPECT_TRUE() instead.
+ EXPECT_TRUE(TestNativeViewHierarchy::kTotalViews > j);
+ }
+ }
+
+ void CheckChangingHierarhy() {
+ size_t i;
+ for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
+ // TODO(georgey): use actual hierarchy changes to send notifications.
+ static_cast<internal::RootView*>(root_views_[i])->
+ NotifyNativeViewHierarchyChanged(false, host_->GetNativeView());
+ static_cast<internal::RootView*>(root_views_[i])->
+ NotifyNativeViewHierarchyChanged(true, host_->GetNativeView());
+ }
+ for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
+ ASSERT_EQ(static_cast<size_t>(2), test_views_[i]->notifications_.size());
+ EXPECT_FALSE(test_views_[i]->notifications_[0].attached);
+ EXPECT_EQ(host_->GetNativeView(),
+ test_views_[i]->notifications_[0].native_view);
+ EXPECT_EQ(root_views_[i], test_views_[i]->notifications_[0].root_view);
+ EXPECT_TRUE(test_views_[i]->notifications_[1].attached);
+ EXPECT_EQ(host_->GetNativeView(),
+ test_views_[i]->notifications_[1].native_view);
+ EXPECT_EQ(root_views_[i], test_views_[i]->notifications_[1].root_view);
+ }
+ }
+
+ NativeViewHost* native_host_;
+ Widget* host_;
+ Widget* windows_[TestNativeViewHierarchy::kTotalViews];
+ View* root_views_[TestNativeViewHierarchy::kTotalViews];
+ TestNativeViewHierarchy* test_views_[TestNativeViewHierarchy::kTotalViews];
+ ViewTest* view_test_;
+};
+
+TEST_F(ViewTest, ChangeNativeViewHierarchyFindRoots) {
+ // TODO(georgey): Fix the test for Linux
+#if defined(OS_WIN)
+ TestChangeNativeViewHierarchy test(this);
+ test.CheckEnumeratingNativeWidgets();
+#endif
+}
+
+TEST_F(ViewTest, ChangeNativeViewHierarchyChangeHierarchy) {
+ // TODO(georgey): Fix the test for Linux
+#if defined(OS_WIN)
+ TestChangeNativeViewHierarchy test(this);
+ test.CheckChangingHierarhy();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Transformations
+////////////////////////////////////////////////////////////////////////////////
+
+class TransformPaintView : public TestView {
+ public:
+ TransformPaintView() {}
+ virtual ~TransformPaintView() {}
+
+ void ClearScheduledPaintRect() {
+ scheduled_paint_rect_ = gfx::Rect();
+ }
+
+ gfx::Rect scheduled_paint_rect() const { return scheduled_paint_rect_; }
+
+ // Overridden from View:
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) {
+ gfx::Rect xrect = ConvertRectToParent(rect);
+ scheduled_paint_rect_ = scheduled_paint_rect_.Union(xrect);
+ }
+
+ private:
+ gfx::Rect scheduled_paint_rect_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransformPaintView);
+};
+
+TEST_F(ViewTest, TransformPaint) {
+ TransformPaintView* v1 = new TransformPaintView();
+ v1->SetBounds(0, 0, 500, 300);
+
+ TestView* v2 = new TestView();
+ v2->SetBounds(100, 100, 200, 100);
+
+ Widget* widget = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget->Init(params);
+ widget->Show();
+ View* root = widget->GetRootView();
+
+ root->AddChildView(v1);
+ v1->AddChildView(v2);
+
+ // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|.
+ v1->ClearScheduledPaintRect();
+ v2->SchedulePaint();
+
+ EXPECT_EQ(gfx::Rect(100, 100, 200, 100), v1->scheduled_paint_rect());
+
+ // Rotate |v1| counter-clockwise.
+ ui::Transform transform;
+ RotateCounterclockwise(transform);
+ transform.SetTranslateY(500.0f);
+ v1->SetTransform(transform);
+
+ // |v2| now occupies (100, 200) to (200, 400) in |root|.
+
+ v1->ClearScheduledPaintRect();
+ v2->SchedulePaint();
+
+ EXPECT_EQ(gfx::Rect(100, 200, 100, 200), v1->scheduled_paint_rect());
+
+ widget->CloseNow();
+}
+
+TEST_F(ViewTest, TransformEvent) {
+ TestView* v1 = new TestView();
+ v1->SetBounds(0, 0, 500, 300);
+
+ TestView* v2 = new TestView();
+ v2->SetBounds(100, 100, 200, 100);
+
+ Widget* widget = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget->Init(params);
+ View* root = widget->GetRootView();
+
+ root->AddChildView(v1);
+ v1->AddChildView(v2);
+
+ // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|.
+
+ // Rotate |v1| counter-clockwise.
+ ui::Transform transform(v1->GetTransform());
+ RotateCounterclockwise(transform);
+ transform.SetTranslateY(500.0f);
+ v1->SetTransform(transform);
+
+ // |v2| now occupies (100, 200) to (200, 400) in |root|.
+ v1->Reset();
+ v2->Reset();
+
+ MouseEvent pressed(ui::ET_MOUSE_PRESSED,
+ 110, 210,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(pressed);
+ EXPECT_EQ(0, v1->last_mouse_event_type_);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
+ EXPECT_EQ(190, v2->location_.x());
+ EXPECT_EQ(10, v2->location_.y());
+
+ MouseEvent released(ui::ET_MOUSE_RELEASED, 0, 0, 0);
+ root->OnMouseReleased(released);
+
+ // Now rotate |v2| inside |v1| clockwise.
+ transform = v2->GetTransform();
+ RotateClockwise(transform);
+ transform.SetTranslateX(100.0f);
+ v2->SetTransform(transform);
+
+ // Now, |v2| occupies (100, 100) to (200, 300) in |v1|, and (100, 300) to
+ // (300, 400) in |root|.
+
+ v1->Reset();
+ v2->Reset();
+
+ MouseEvent p2(ui::ET_MOUSE_PRESSED,
+ 110, 320,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(p2);
+ EXPECT_EQ(0, v1->last_mouse_event_type_);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
+ EXPECT_EQ(10, v2->location_.x());
+ EXPECT_EQ(20, v2->location_.y());
+
+ root->OnMouseReleased(released);
+
+ v1->SetTransform(ui::Transform());
+ v2->SetTransform(ui::Transform());
+
+ TestView* v3 = new TestView();
+ v3->SetBounds(10, 10, 20, 30);
+ v2->AddChildView(v3);
+
+ // Rotate |v3| clockwise with respect to |v2|.
+ transform = v1->GetTransform();
+ RotateClockwise(transform);
+ transform.SetTranslateX(30.0f);
+ v3->SetTransform(transform);
+
+ // Scale |v2| with respect to |v1| along both axis.
+ transform = v2->GetTransform();
+ transform.SetScale(0.8f, 0.5f);
+ v2->SetTransform(transform);
+
+ // |v3| occupies (108, 105) to (132, 115) in |root|.
+
+ v1->Reset();
+ v2->Reset();
+ v3->Reset();
+
+ MouseEvent p3(ui::ET_MOUSE_PRESSED,
+ 112, 110,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(p3);
+
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
+ EXPECT_EQ(10, v3->location_.x());
+ EXPECT_EQ(25, v3->location_.y());
+
+ root->OnMouseReleased(released);
+
+ v1->SetTransform(ui::Transform());
+ v2->SetTransform(ui::Transform());
+ v3->SetTransform(ui::Transform());
+
+ v1->Reset();
+ v2->Reset();
+ v3->Reset();
+
+ // Rotate |v3| clockwise with respect to |v2|, and scale it along both axis.
+ transform = v3->GetTransform();
+ RotateClockwise(transform);
+ transform.SetTranslateX(30.0f);
+ // Rotation sets some scaling transformation. Using SetScale would overwrite
+ // that and pollute the rotation. So combine the scaling with the existing
+ // transforamtion.
+ transform.ConcatScale(0.8f, 0.5f);
+ v3->SetTransform(transform);
+
+ // Translate |v2| with respect to |v1|.
+ transform = v2->GetTransform();
+ transform.SetTranslate(10, 10);
+ v2->SetTransform(transform);
+
+ // |v3| now occupies (120, 120) to (144, 130) in |root|.
+
+ MouseEvent p4(ui::ET_MOUSE_PRESSED,
+ 124, 125,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(p4);
+
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
+ EXPECT_EQ(10, v3->location_.x());
+ EXPECT_EQ(25, v3->location_.y());
+
+ root->OnMouseReleased(released);
+
+ widget->CloseNow();
+}
+
+TEST_F(ViewTest, TransformVisibleBound) {
+ gfx::Rect viewport_bounds(0, 0, 100, 100);
+
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = viewport_bounds;
+ widget->Init(params);
+ widget->GetRootView()->SetBoundsRect(viewport_bounds);
+
+ View* viewport = new View;
+ widget->SetContentsView(viewport);
+ View* contents = new View;
+ viewport->AddChildView(contents);
+ viewport->SetBoundsRect(viewport_bounds);
+ contents->SetBounds(0, 0, 100, 200);
+
+ View* child = new View;
+ contents->AddChildView(child);
+ child->SetBounds(10, 90, 50, 50);
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 10), child->GetVisibleBounds());
+
+ // Rotate |child| counter-clockwise
+ ui::Transform transform;
+ RotateCounterclockwise(transform);
+ transform.SetTranslateY(50.0f);
+ child->SetTransform(transform);
+ EXPECT_EQ(gfx::Rect(40, 0, 10, 50), child->GetVisibleBounds());
+
+ widget->CloseNow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// OnVisibleBoundsChanged()
+
+class VisibleBoundsView : public View {
+ public:
+ VisibleBoundsView() : received_notification_(false) {}
+ virtual ~VisibleBoundsView() {}
+
+ bool received_notification() const { return received_notification_; }
+ void set_received_notification(bool received) {
+ received_notification_ = received;
+ }
+
+ private:
+ // Overridden from View:
+ virtual bool NeedsNotificationWhenVisibleBoundsChange() const {
+ return true;
+ }
+ virtual void OnVisibleBoundsChanged() {
+ received_notification_ = true;
+ }
+
+ bool received_notification_;
+
+ DISALLOW_COPY_AND_ASSIGN(VisibleBoundsView);
+};
+
+TEST_F(ViewTest, OnVisibleBoundsChanged) {
+ gfx::Rect viewport_bounds(0, 0, 100, 100);
+
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = viewport_bounds;
+ widget->Init(params);
+ widget->GetRootView()->SetBoundsRect(viewport_bounds);
+
+ View* viewport = new View;
+ widget->SetContentsView(viewport);
+ View* contents = new View;
+ viewport->AddChildView(contents);
+ viewport->SetBoundsRect(viewport_bounds);
+ contents->SetBounds(0, 0, 100, 200);
+
+ // Create a view that cares about visible bounds notifications, and position
+ // it just outside the visible bounds of the viewport.
+ VisibleBoundsView* child = new VisibleBoundsView;
+ contents->AddChildView(child);
+ child->SetBounds(10, 110, 50, 50);
+
+ // The child bound should be fully clipped.
+ EXPECT_TRUE(child->GetVisibleBounds().IsEmpty());
+
+ // Now scroll the contents, but not enough to make the child visible.
+ contents->SetY(contents->y() - 1);
+
+ // We should have received the notification since the visible bounds may have
+ // changed (even though they didn't).
+ EXPECT_TRUE(child->received_notification());
+ EXPECT_TRUE(child->GetVisibleBounds().IsEmpty());
+ child->set_received_notification(false);
+
+ // Now scroll the contents, this time by enough to make the child visible by
+ // one pixel.
+ contents->SetY(contents->y() - 10);
+ EXPECT_TRUE(child->received_notification());
+ EXPECT_EQ(1, child->GetVisibleBounds().height());
+ child->set_received_notification(false);
+
+ widget->CloseNow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BoundsChanged()
+
+TEST_F(ViewTest, SetBoundsPaint) {
+ TestView top_view;
+ TestView* child_view = new TestView;
+
+ top_view.SetBounds(0, 0, 100, 100);
+ top_view.scheduled_paint_rects_.clear();
+ child_view->SetBounds(10, 10, 20, 20);
+ top_view.AddChildView(child_view);
+
+ top_view.scheduled_paint_rects_.clear();
+ child_view->SetBounds(30, 30, 20, 20);
+ EXPECT_EQ(2U, top_view.scheduled_paint_rects_.size());
+
+ // There should be 2 rects, spanning from (10, 10) to (50, 50).
+ gfx::Rect paint_rect =
+ top_view.scheduled_paint_rects_[0].Union(
+ top_view.scheduled_paint_rects_[1]);
+ EXPECT_EQ(gfx::Rect(10, 10, 40, 40), paint_rect);
+}
+
+// Tests conversion methods with a transform.
+TEST_F(ViewTest, ConvertPointToViewWithTransform) {
+ TestView top_view;
+ TestView* child = new TestView;
+ TestView* child_child = new TestView;
+
+ top_view.AddChildView(child);
+ child->AddChildView(child_child);
+
+ top_view.SetBounds(0, 0, 1000, 1000);
+
+ child->SetBounds(7, 19, 500, 500);
+ ui::Transform transform;
+ transform.SetScale(3.0f, 4.0f);
+ child->SetTransform(transform);
+
+ child_child->SetBounds(17, 13, 100, 100);
+ transform = ui::Transform();
+ transform.SetScale(5.0f, 7.0f);
+ child_child->SetTransform(transform);
+
+ // Sanity check to make sure basic transforms act as expected.
+ {
+ ui::Transform transform;
+ transform.ConcatTranslate(1, 1);
+ transform.ConcatScale(100, 55);
+ transform.ConcatTranslate(110, -110);
+
+ // convert to a 3x3 matrix.
+ const SkMatrix& matrix = transform.matrix();
+
+ EXPECT_EQ(210, matrix.getTranslateX());
+ EXPECT_EQ(-55, matrix.getTranslateY());
+ EXPECT_EQ(100, matrix.getScaleX());
+ EXPECT_EQ(55, matrix.getScaleY());
+ EXPECT_EQ(0, matrix.getSkewX());
+ EXPECT_EQ(0, matrix.getSkewY());
+ }
+
+ {
+ ui::Transform transform;
+ transform.SetTranslate(1, 1);
+ ui::Transform t2;
+ t2.SetScale(100, 55);
+ ui::Transform t3;
+ t3.SetTranslate(110, -110);
+ transform.ConcatTransform(t2);
+ transform.ConcatTransform(t3);
+
+ // convert to a 3x3 matrix
+ const SkMatrix& matrix = transform.matrix();
+
+ EXPECT_EQ(210, matrix.getTranslateX());
+ EXPECT_EQ(-55, matrix.getTranslateY());
+ EXPECT_EQ(100, matrix.getScaleX());
+ EXPECT_EQ(55, matrix.getScaleY());
+ EXPECT_EQ(0, matrix.getSkewX());
+ EXPECT_EQ(0, matrix.getSkewY());
+ }
+
+ // Conversions from child->top and top->child.
+ {
+ gfx::Point point(5, 5);
+ View::ConvertPointToView(child, &top_view, &point);
+ EXPECT_EQ(22, point.x());
+ EXPECT_EQ(39, point.y());
+
+ point.SetPoint(22, 39);
+ View::ConvertPointToView(&top_view, child, &point);
+ EXPECT_EQ(5, point.x());
+ EXPECT_EQ(5, point.y());
+ }
+
+ // Conversions from child_child->top and top->child_child.
+ {
+ gfx::Point point(5, 5);
+ View::ConvertPointToView(child_child, &top_view, &point);
+ EXPECT_EQ(133, point.x());
+ EXPECT_EQ(211, point.y());
+
+ point.SetPoint(133, 211);
+ View::ConvertPointToView(&top_view, child_child, &point);
+ EXPECT_EQ(5, point.x());
+ EXPECT_EQ(5, point.y());
+ }
+
+ // Conversions from child_child->child and child->child_child
+ {
+ gfx::Point point(5, 5);
+ View::ConvertPointToView(child_child, child, &point);
+ EXPECT_EQ(42, point.x());
+ EXPECT_EQ(48, point.y());
+
+ point.SetPoint(42, 48);
+ View::ConvertPointToView(child, child_child, &point);
+ EXPECT_EQ(5, point.x());
+ EXPECT_EQ(5, point.y());
+ }
+
+ // Conversions from top_view to child with a value that should be negative.
+ // This ensures we don't round up with negative numbers.
+ {
+ gfx::Point point(6, 18);
+ View::ConvertPointToView(&top_view, child, &point);
+ EXPECT_EQ(-1, point.x());
+ EXPECT_EQ(-1, point.y());
+ }
+}
+
+// Tests conversion methods for rectangles.
+TEST_F(ViewTest, ConvertRectWithTransform) {
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget->Init(params);
+ View* root = widget->GetRootView();
+
+ TestView* v1 = new TestView;
+ TestView* v2 = new TestView;
+ root->AddChildView(v1);
+ v1->AddChildView(v2);
+
+ v1->SetBounds(10, 10, 500, 500);
+ v2->SetBounds(20, 20, 100, 200);
+
+ // |v2| now occupies (30, 30) to (130, 230) in |widget|
+ gfx::Rect rect(5, 5, 15, 40);
+ EXPECT_EQ(gfx::Rect(25, 25, 15, 40), v2->ConvertRectToParent(rect));
+ EXPECT_EQ(gfx::Rect(35, 35, 15, 40), v2->ConvertRectToWidget(rect));
+
+ // Rotate |v2|
+ ui::Transform t2;
+ RotateCounterclockwise(t2);
+ t2.SetTranslateY(100.0f);
+ v2->SetTransform(t2);
+
+ // |v2| now occupies (30, 30) to (230, 130) in |widget|
+ EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect));
+ EXPECT_EQ(gfx::Rect(35, 110, 40, 15), v2->ConvertRectToWidget(rect));
+
+ // Scale down |v1|
+ ui::Transform t1;
+ t1.SetScale(0.5, 0.5);
+ v1->SetTransform(t1);
+
+ // The rectangle should remain the same for |v1|.
+ EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect));
+
+ // |v2| now occupies (20, 20) to (120, 70) in |widget|
+ // There are some rounding of floating values here. These values may change if
+ // floating operations are improved/changed.
+ EXPECT_EQ(gfx::Rect(22, 60, 20, 7), v2->ConvertRectToWidget(rect));
+
+ widget->CloseNow();
+}
+
+class ObserverView : public View {
+ public:
+ ObserverView();
+ virtual ~ObserverView();
+
+ void ResetTestState();
+
+ bool child_added() const { return child_added_; }
+ bool child_removed() const { return child_removed_; }
+ const View* parent_view() const { return parent_view_; }
+ const View* child_view() const { return child_view_; }
+
+ private:
+ // View:
+ virtual void ViewHierarchyChanged(bool is_add,
+ View* parent,
+ View* child) OVERRIDE;
+
+ bool child_added_;
+ bool child_removed_;
+ View* parent_view_;
+ View* child_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(ObserverView);
+};
+
+ObserverView::ObserverView()
+ : child_added_(false),
+ child_removed_(false),
+ parent_view_(NULL),
+ child_view_(NULL) {
+}
+
+ObserverView::~ObserverView() {}
+
+void ObserverView::ResetTestState() {
+ child_added_ = false;
+ child_removed_ = false;
+ parent_view_ = NULL;
+ child_view_ = NULL;
+}
+
+void ObserverView::ViewHierarchyChanged(bool is_add,
+ View* parent,
+ View* child) {
+ if (is_add)
+ child_added_ = true;
+ else
+ child_removed_ = true;
+
+ parent_view_ = parent;
+ child_view_ = child;
+}
+
+// Verifies that the ViewHierarchyChanged() notification is sent correctly when
+// a child view is added or removed to all the views in the hierarchy (up and
+// down).
+// The tree looks like this:
+// v1
+// +-- v2
+// +-- v3
+TEST_F(ViewTest, ViewHierarchyChanged) {
+ ObserverView v1;
+
+ ObserverView* v3 = new ObserverView();
+
+ // Add |v3| to |v2|.
+ scoped_ptr<ObserverView> v2(new ObserverView());
+ v2->AddChildView(v3);
+
+ // Make sure both |v2| and |v3| receive the ViewHierarchyChanged()
+ // notification.
+ EXPECT_TRUE(v2->child_added());
+ EXPECT_FALSE(v2->child_removed());
+ EXPECT_EQ(v2.get(), v2->parent_view());
+ EXPECT_EQ(v3, v2->child_view());
+
+ EXPECT_TRUE(v3->child_added());
+ EXPECT_FALSE(v3->child_removed());
+ EXPECT_EQ(v2.get(), v3->parent_view());
+ EXPECT_EQ(v3, v3->child_view());
+
+ // Reset everything to the initial state.
+ v2->ResetTestState();
+ v3->ResetTestState();
+
+ // Add |v2| to v1.
+ v1.AddChildView(v2.get());
+
+ // Verifies that |v2| is the child view *added* and the parent view is |v1|.
+ // Make sure all the views (v1, v2, v3) received _that_ information.
+ EXPECT_TRUE(v1.child_added());
+ EXPECT_FALSE(v1.child_removed());
+ EXPECT_EQ(&v1, v1.parent_view());
+ EXPECT_EQ(v2.get(), v1.child_view());
+
+ EXPECT_TRUE(v2->child_added());
+ EXPECT_FALSE(v2->child_removed());
+ EXPECT_EQ(&v1, v2->parent_view());
+ EXPECT_EQ(v2.get(), v2->child_view());
+
+ EXPECT_TRUE(v3->child_added());
+ EXPECT_FALSE(v3->child_removed());
+ EXPECT_EQ(&v1, v3->parent_view());
+ EXPECT_EQ(v2.get(), v3->child_view());
+
+ // Reset everything to the initial state.
+ v1.ResetTestState();
+ v2->ResetTestState();
+ v3->ResetTestState();
+
+ // Remove |v2| from |v1|.
+ v1.RemoveChildView(v2.get());
+
+ // Verifies that |v2| is the child view *removed* and the parent view is |v1|.
+ // Make sure all the views (v1, v2, v3) received _that_ information.
+ EXPECT_FALSE(v1.child_added());
+ EXPECT_TRUE(v1.child_removed());
+ EXPECT_EQ(&v1, v1.parent_view());
+ EXPECT_EQ(v2.get(), v1.child_view());
+
+ EXPECT_FALSE(v2->child_added());
+ EXPECT_TRUE(v2->child_removed());
+ EXPECT_EQ(&v1, v2->parent_view());
+ EXPECT_EQ(v2.get(), v2->child_view());
+
+ EXPECT_FALSE(v3->child_added());
+ EXPECT_TRUE(v3->child_removed());
+ EXPECT_EQ(&v1, v3->parent_view());
+ EXPECT_EQ(v3, v3->child_view());
+}
+
+// Verifies if the child views added under the root are all deleted when calling
+// RemoveAllChildViews.
+// The tree looks like this:
+// root
+// +-- child1
+// +-- foo
+// +-- bar0
+// +-- bar1
+// +-- bar2
+// +-- child2
+// +-- child3
+TEST_F(ViewTest, RemoveAllChildViews) {
+ View root;
+
+ View* child1 = new View;
+ root.AddChildView(child1);
+
+ for (int i = 0; i < 2; ++i)
+ root.AddChildView(new View);
+
+ View* foo = new View;
+ child1->AddChildView(foo);
+
+ // Add some nodes to |foo|.
+ for (int i = 0; i < 3; ++i)
+ foo->AddChildView(new View);
+
+ EXPECT_EQ(3, root.child_count());
+ EXPECT_EQ(1, child1->child_count());
+ EXPECT_EQ(3, foo->child_count());
+
+ // Now remove all child views from root.
+ root.RemoveAllChildViews(true);
+
+ EXPECT_EQ(0, root.child_count());
+ EXPECT_FALSE(root.has_children());
+}
+
+TEST_F(ViewTest, Contains) {
+ View v1;
+ View* v2 = new View;
+ View* v3 = new View;
+
+ v1.AddChildView(v2);
+ v2->AddChildView(v3);
+
+ EXPECT_FALSE(v1.Contains(NULL));
+ EXPECT_TRUE(v1.Contains(&v1));
+ EXPECT_TRUE(v1.Contains(v2));
+ EXPECT_TRUE(v1.Contains(v3));
+
+ EXPECT_FALSE(v2->Contains(NULL));
+ EXPECT_TRUE(v2->Contains(v2));
+ EXPECT_FALSE(v2->Contains(&v1));
+ EXPECT_TRUE(v2->Contains(v3));
+
+ EXPECT_FALSE(v3->Contains(NULL));
+ EXPECT_TRUE(v3->Contains(v3));
+ EXPECT_FALSE(v3->Contains(&v1));
+ EXPECT_FALSE(v3->Contains(v2));
+}
+
+// Verifies if GetIndexOf() returns the correct index for the specified child
+// view.
+// The tree looks like this:
+// root
+// +-- child1
+// +-- foo1
+// +-- child2
+TEST_F(ViewTest, GetIndexOf) {
+ View root;
+
+ View* child1 = new View;
+ root.AddChildView(child1);
+
+ View* child2 = new View;
+ root.AddChildView(child2);
+
+ View* foo1 = new View;
+ child1->AddChildView(foo1);
+
+ EXPECT_EQ(-1, root.GetIndexOf(NULL));
+ EXPECT_EQ(-1, root.GetIndexOf(&root));
+ EXPECT_EQ(0, root.GetIndexOf(child1));
+ EXPECT_EQ(1, root.GetIndexOf(child2));
+ EXPECT_EQ(-1, root.GetIndexOf(foo1));
+
+ EXPECT_EQ(-1, child1->GetIndexOf(NULL));
+ EXPECT_EQ(-1, child1->GetIndexOf(&root));
+ EXPECT_EQ(-1, child1->GetIndexOf(child1));
+ EXPECT_EQ(-1, child1->GetIndexOf(child2));
+ EXPECT_EQ(0, child1->GetIndexOf(foo1));
+
+ EXPECT_EQ(-1, child2->GetIndexOf(NULL));
+ EXPECT_EQ(-1, child2->GetIndexOf(&root));
+ EXPECT_EQ(-1, child2->GetIndexOf(child2));
+ EXPECT_EQ(-1, child2->GetIndexOf(child1));
+ EXPECT_EQ(-1, child2->GetIndexOf(foo1));
+}
+
+// Verifies that the child views can be reordered correctly.
+TEST_F(ViewTest, ReorderChildren) {
+ View root;
+
+ View* child = new View();
+ root.AddChildView(child);
+
+ View* foo1 = new View();
+ child->AddChildView(foo1);
+ View* foo2 = new View();
+ child->AddChildView(foo2);
+ View* foo3 = new View();
+ child->AddChildView(foo3);
+ foo1->set_focusable(true);
+ foo2->set_focusable(true);
+ foo3->set_focusable(true);
+
+ ASSERT_EQ(0, child->GetIndexOf(foo1));
+ ASSERT_EQ(1, child->GetIndexOf(foo2));
+ ASSERT_EQ(2, child->GetIndexOf(foo3));
+ ASSERT_EQ(foo2, foo1->GetNextFocusableView());
+ ASSERT_EQ(foo3, foo2->GetNextFocusableView());
+ ASSERT_EQ(NULL, foo3->GetNextFocusableView());
+
+ // Move |foo2| at the end.
+ child->ReorderChildView(foo2, -1);
+ ASSERT_EQ(0, child->GetIndexOf(foo1));
+ ASSERT_EQ(1, child->GetIndexOf(foo3));
+ ASSERT_EQ(2, child->GetIndexOf(foo2));
+ ASSERT_EQ(foo3, foo1->GetNextFocusableView());
+ ASSERT_EQ(foo2, foo3->GetNextFocusableView());
+ ASSERT_EQ(NULL, foo2->GetNextFocusableView());
+
+ // Move |foo1| at the end.
+ child->ReorderChildView(foo1, -1);
+ ASSERT_EQ(0, child->GetIndexOf(foo3));
+ ASSERT_EQ(1, child->GetIndexOf(foo2));
+ ASSERT_EQ(2, child->GetIndexOf(foo1));
+ ASSERT_EQ(NULL, foo1->GetNextFocusableView());
+ ASSERT_EQ(foo2, foo1->GetPreviousFocusableView());
+ ASSERT_EQ(foo2, foo3->GetNextFocusableView());
+ ASSERT_EQ(foo1, foo2->GetNextFocusableView());
+
+ // Move |foo2| to the front.
+ child->ReorderChildView(foo2, 0);
+ ASSERT_EQ(0, child->GetIndexOf(foo2));
+ ASSERT_EQ(1, child->GetIndexOf(foo3));
+ ASSERT_EQ(2, child->GetIndexOf(foo1));
+ ASSERT_EQ(NULL, foo1->GetNextFocusableView());
+ ASSERT_EQ(foo3, foo1->GetPreviousFocusableView());
+ ASSERT_EQ(foo3, foo2->GetNextFocusableView());
+ ASSERT_EQ(foo1, foo3->GetNextFocusableView());
+}
+
+// Verifies that GetViewByID returns the correctly child view from the specified
+// ID.
+// The tree looks like this:
+// v1
+// +-- v2
+// +-- v3
+// +-- v4
+TEST_F(ViewTest, GetViewByID) {
+ View v1;
+ const int kV1ID = 1;
+ v1.set_id(kV1ID);
+
+ View v2;
+ const int kV2ID = 2;
+ v2.set_id(kV2ID);
+
+ View v3;
+ const int kV3ID = 3;
+ v3.set_id(kV3ID);
+
+ View v4;
+ const int kV4ID = 4;
+ v4.set_id(kV4ID);
+
+ const int kV5ID = 5;
+
+ v1.AddChildView(&v2);
+ v2.AddChildView(&v3);
+ v2.AddChildView(&v4);
+
+ EXPECT_EQ(&v1, v1.GetViewByID(kV1ID));
+ EXPECT_EQ(&v2, v1.GetViewByID(kV2ID));
+ EXPECT_EQ(&v4, v1.GetViewByID(kV4ID));
+
+ EXPECT_EQ(NULL, v1.GetViewByID(kV5ID)); // No V5 exists.
+ EXPECT_EQ(NULL, v2.GetViewByID(kV1ID)); // It can get only from child views.
+
+ const int kGroup = 1;
+ v3.SetGroup(kGroup);
+ v4.SetGroup(kGroup);
+
+ View::Views views;
+ v1.GetViewsInGroup(kGroup, &views);
+ EXPECT_EQ(2U, views.size());
+
+ View::Views::const_iterator i(std::find(views.begin(), views.end(), &v3));
+ EXPECT_NE(views.end(), i);
+
+ i = std::find(views.begin(), views.end(), &v4);
+ EXPECT_NE(views.end(), i);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Layers
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(VIEWS_COMPOSITOR)
+
+namespace {
+
+// Test implementation of LayerAnimator.
+class TestLayerAnimator : public ui::LayerAnimator {
+ public:
+ TestLayerAnimator();
+
+ const gfx::Rect& last_bounds() const { return last_bounds_; }
+
+ // LayerAnimator.
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+
+ private:
+ gfx::Rect last_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestLayerAnimator);
+};
+
+TestLayerAnimator::TestLayerAnimator()
+ : ui::LayerAnimator(base::TimeDelta::FromMilliseconds(0)) {
+}
+
+void TestLayerAnimator::SetBounds(const gfx::Rect& bounds) {
+ last_bounds_ = bounds;
+}
+
+} // namespace
+
+class ViewLayerTest : public ViewsTestBase {
+ public:
+ ViewLayerTest() : widget_(NULL), old_use_acceleration_(false) {}
+
+ virtual ~ViewLayerTest() {
+ }
+
+ // Returns the Layer used by the RootView.
+ ui::Layer* GetRootLayer() {
+#if defined(USE_AURA)
+ ui::Layer* root_layer = NULL;
+ gfx::Point origin;
+ widget()->CalculateOffsetToAncestorWithLayer(&origin, &root_layer);
+ return root_layer;
+#else
+ return widget()->GetRootView()->layer();
+#endif
+ }
+
+ virtual void SetUp() OVERRIDE {
+ ViewTest::SetUp();
+ old_use_acceleration_ = View::get_use_acceleration_when_possible();
+ View::set_use_acceleration_when_possible(true);
+
+ ui::TestTexture::reset_live_count();
+
+ widget_ = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(50, 50, 200, 200);
+ widget_->Init(params);
+ widget_->Show();
+ widget_->GetRootView()->SetBounds(0, 0, 200, 200);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ View::set_use_acceleration_when_possible(old_use_acceleration_);
+ widget_->CloseNow();
+ Widget::SetPureViews(false);
+ ViewsTestBase::TearDown();
+ }
+
+ Widget* widget() { return widget_; }
+
+ private:
+ Widget* widget_;
+ bool old_use_acceleration_;
+};
+
+#if !defined(USE_AURA)
+// This test assumes a particular layer hierarchy that isn't valid for aura.
+// Ensures the RootView has a layer and its set up correctly.
+TEST_F(ViewLayerTest, RootState) {
+ ui::Layer* layer = widget()->GetRootView()->layer();
+ ASSERT_TRUE(layer);
+ EXPECT_FALSE(layer->parent());
+ EXPECT_EQ(0u, layer->children().size());
+ EXPECT_FALSE(layer->transform().HasChange());
+ EXPECT_EQ(widget()->GetRootView()->bounds(), layer->bounds());
+ EXPECT_TRUE(layer->GetCompositor() != NULL);
+}
+
+// Verifies that the complete bounds of a texture are updated if the texture
+// needs to be refreshed and paint with a clip is invoked.
+// This test invokes OnNativeWidgetPaintAccelerated, which is not used by aura.
+TEST_F(ViewLayerTest, PaintAll) {
+ View* view = widget()->GetRootView();
+ ui::Layer* layer = GetRootLayer();
+ view->SetBounds(0, 0, 200, 200);
+ widget()->OnNativeWidgetPaintAccelerated(gfx::Rect(0, 0, 1, 1));
+ ASSERT_TRUE(layer != NULL);
+ const ui::TestTexture* texture =
+ static_cast<const ui::TestTexture*>(layer->texture());
+ ASSERT_TRUE(texture != NULL);
+ EXPECT_EQ(view->GetLocalBounds(), texture->bounds_of_last_paint());
+}
+#endif
+
+TEST_F(ViewLayerTest, LayerToggling) {
+ // Because we lazily create textures the calls to DrawTree are necessary to
+ // ensure we trigger creation of textures.
+#if defined(USE_AURA)
+ ui::Layer* root_layer = NULL;
+ gfx::Point origin;
+ widget()->CalculateOffsetToAncestorWithLayer(&origin, &root_layer);
+#else
+ ui::Layer* root_layer = widget()->GetRootView()->layer();
+#endif
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+#if !defined(USE_WEBKIT_COMPOSITOR)
+ // TODO(piman): with the webkit compositor, we don't create Textures on
+ // Layers. We're not supposed to be calling Layer::DrawTree. This test needs
+ // refactoring to fully work in that case.
+ root_layer->DrawTree();
+ ui::TestTexture::reset_live_count();
+#endif
+
+ // Create v1, give it a bounds and verify everything is set up correctly.
+ View* v1 = new View;
+ v1->SetPaintToLayer(true);
+#if !defined(USE_WEBKIT_COMPOSITOR)
+ root_layer->DrawTree();
+ EXPECT_EQ(0, ui::TestTexture::live_count());
+#endif
+ EXPECT_TRUE(v1->layer() != NULL);
+ v1->SetBounds(20, 30, 140, 150);
+ content_view->AddChildView(v1);
+#if !defined(USE_WEBKIT_COMPOSITOR)
+ root_layer->DrawTree();
+ EXPECT_EQ(1, ui::TestTexture::live_count());
+#endif
+ ASSERT_TRUE(v1->layer() != NULL);
+ EXPECT_EQ(root_layer, v1->layer()->parent());
+ EXPECT_EQ(gfx::Rect(20, 30, 140, 150), v1->layer()->bounds());
+
+ // Create v2 as a child of v1 and do basic assertion testing.
+ View* v2 = new View;
+ v1->AddChildView(v2);
+ EXPECT_TRUE(v2->layer() == NULL);
+ v2->SetBounds(10, 20, 30, 40);
+ v2->SetPaintToLayer(true);
+#if !defined(USE_WEBKIT_COMPOSITOR)
+ root_layer->DrawTree();
+ EXPECT_EQ(2, ui::TestTexture::live_count());
+#endif
+ ASSERT_TRUE(v2->layer() != NULL);
+ EXPECT_EQ(v1->layer(), v2->layer()->parent());
+ EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds());
+
+ // Turn off v1s layer. v2 should still have a layer but its parent should have
+ // changed.
+ v1->SetPaintToLayer(false);
+#if !defined(USE_WEBKIT_COMPOSITOR)
+ root_layer->DrawTree();
+ EXPECT_EQ(1, ui::TestTexture::live_count());
+#endif
+ EXPECT_TRUE(v1->layer() == NULL);
+ EXPECT_TRUE(v2->layer() != NULL);
+ EXPECT_EQ(root_layer, v2->layer()->parent());
+ ASSERT_EQ(1u, root_layer->children().size());
+ EXPECT_EQ(root_layer->children()[0], v2->layer());
+ // The bounds of the layer should have changed to be relative to the root view
+ // now.
+ EXPECT_EQ(gfx::Rect(30, 50, 30, 40), v2->layer()->bounds());
+
+ // Make v1 have a layer again and verify v2s layer is wired up correctly.
+ ui::Transform transform;
+ transform.SetScale(2.0f, 2.0f);
+ v1->SetTransform(transform);
+#if !defined(USE_WEBKIT_COMPOSITOR)
+ root_layer->DrawTree();
+ EXPECT_EQ(2, ui::TestTexture::live_count());
+#endif
+ EXPECT_TRUE(v1->layer() != NULL);
+ EXPECT_TRUE(v2->layer() != NULL);
+ EXPECT_EQ(root_layer, v1->layer()->parent());
+ EXPECT_EQ(v1->layer(), v2->layer()->parent());
+ ASSERT_EQ(1u, root_layer->children().size());
+ EXPECT_EQ(root_layer->children()[0], v1->layer());
+ ASSERT_EQ(1u, v1->layer()->children().size());
+ EXPECT_EQ(v1->layer()->children()[0], v2->layer());
+ EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds());
+}
+
+// Verifies turning on a layer wires up children correctly.
+TEST_F(ViewLayerTest, NestedLayerToggling) {
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+ // Create v1, give it a bounds and verify everything is set up correctly.
+ View* v1 = new View;
+ content_view->AddChildView(v1);
+ v1->SetBounds(20, 30, 140, 150);
+
+ View* v2 = new View;
+ v1->AddChildView(v2);
+
+ View* v3 = new View;
+ v3->SetPaintToLayer(true);
+ v2->AddChildView(v3);
+ ASSERT_TRUE(v3->layer() != NULL);
+
+ // At this point we have v1-v2-v3. v3 has a layer, v1 and v2 don't.
+
+ v1->SetPaintToLayer(true);
+ EXPECT_EQ(v1->layer(), v3->layer()->parent());
+}
+
+TEST_F(ViewLayerTest, LayerAnimator) {
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+ View* v1 = new View;
+ content_view->AddChildView(v1);
+ v1->SetPaintToLayer(true);
+ EXPECT_TRUE(v1->layer() != NULL);
+
+ TestLayerAnimator* animator = new TestLayerAnimator();
+ v1->layer()->SetAnimator(animator);
+
+ gfx::Rect bounds(1, 2, 3, 4);
+ v1->SetBoundsRect(bounds);
+ EXPECT_EQ(bounds, animator->last_bounds());
+ // TestLayerAnimator doesn't update the layer.
+ EXPECT_NE(bounds, v1->layer()->bounds());
+}
+
+// Verifies the bounds of a layer are updated if the bounds of ancestor that
+// doesn't have a layer change.
+TEST_F(ViewLayerTest, BoundsChangeWithLayer) {
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+ View* v1 = new View;
+ content_view->AddChildView(v1);
+ v1->SetBounds(20, 30, 140, 150);
+
+ View* v2 = new View;
+ v2->SetBounds(10, 11, 40, 50);
+ v1->AddChildView(v2);
+ v2->SetPaintToLayer(true);
+ ASSERT_TRUE(v2->layer() != NULL);
+ EXPECT_EQ(gfx::Rect(30, 41, 40, 50), v2->layer()->bounds());
+
+ v1->SetPosition(gfx::Point(25, 36));
+ EXPECT_EQ(gfx::Rect(35, 47, 40, 50), v2->layer()->bounds());
+
+ v2->SetPosition(gfx::Point(11, 12));
+ EXPECT_EQ(gfx::Rect(36, 48, 40, 50), v2->layer()->bounds());
+
+ // Bounds of the layer should change even if the view is not invisible.
+ v1->SetVisible(false);
+ v1->SetPosition(gfx::Point(20, 30));
+ EXPECT_EQ(gfx::Rect(31, 42, 40, 50), v2->layer()->bounds());
+
+ v2->SetVisible(false);
+ v2->SetBounds(10, 11, 20, 30);
+ EXPECT_EQ(gfx::Rect(30, 41, 20, 30), v2->layer()->bounds());
+}
+
+// Makes sure a transform persists after toggling the visibility.
+TEST_F(ViewLayerTest, ToggleVisibilityWithTransform) {
+ View* view = new View;
+ ui::Transform transform;
+ transform.SetScale(2.0f, 2.0f);
+ view->SetTransform(transform);
+ widget()->SetContentsView(view);
+ EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
+
+ view->SetVisible(false);
+ EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
+
+ view->SetVisible(true);
+ EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
+}
+
+// Verifies a transform persists after removing/adding a view with a transform.
+TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) {
+ View* view = new View;
+ ui::Transform transform;
+ transform.SetScale(2.0f, 2.0f);
+ view->SetTransform(transform);
+ widget()->SetContentsView(view);
+ EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
+ ASSERT_TRUE(view->layer() != NULL);
+ EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0));
+
+ View* parent = view->parent();
+ parent->RemoveChildView(view);
+ parent->AddChildView(view);
+
+ EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
+ ASSERT_TRUE(view->layer() != NULL);
+ EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0));
+}
+
+// Makes sure that layer visibility is correct after toggling View visibility.
+TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) {
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+ // The view isn't attached to a widget or a parent view yet. But it should
+ // still have a layer, but the layer should not be attached to the root
+ // layer.
+ View* v1 = new View;
+ v1->SetPaintToLayer(true);
+ EXPECT_TRUE(v1->layer());
+ EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
+ v1->layer()));
+
+ // Once the view is attached to a widget, its layer should be attached to the
+ // root layer and visible.
+ content_view->AddChildView(v1);
+ EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
+ v1->layer()));
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+
+ v1->SetVisible(false);
+ EXPECT_FALSE(v1->layer()->IsDrawn());
+
+ v1->SetVisible(true);
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+
+ widget()->Hide();
+ EXPECT_FALSE(v1->layer()->IsDrawn());
+
+ widget()->Show();
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+}
+
+// Test that a hole in a layer is correctly created regardless of whether
+// the opacity attribute is set before or after the layer is created.
+TEST_F(ViewLayerTest, ToggleOpacityWithLayer) {
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+ View* parent_view = new View;
+ content_view->AddChildView(parent_view);
+ parent_view->SetPaintToLayer(true);
+ parent_view->SetBounds(0, 0, 400, 400);
+
+ View* child_view = new View;
+ child_view->SetBounds(50, 50, 100, 100);
+ parent_view->AddChildView(child_view);
+
+ widget()->GetCompositor()->Draw(false);
+
+ ASSERT_TRUE(child_view->layer() == NULL);
+ child_view->SetPaintToLayer(true);
+ child_view->SetFillsBoundsOpaquely(true);
+ widget()->GetCompositor()->Draw(false);
+ ASSERT_TRUE(child_view->layer());
+ EXPECT_EQ(
+ gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect());
+
+ child_view->SetFillsBoundsOpaquely(false);
+ widget()->GetCompositor()->Draw(false);
+ EXPECT_TRUE(parent_view->layer()->hole_rect().IsEmpty());
+}
+
+// Test that a hole in a layer always corresponds to the bounds of opaque
+// layers.
+TEST_F(ViewLayerTest, MultipleOpaqueLayers) {
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+ View* parent_view = new View;
+ parent_view->SetPaintToLayer(true);
+ parent_view->SetBounds(0, 0, 400, 400);
+ content_view->AddChildView(parent_view);
+
+ View* child_view1 = new View;
+ child_view1->SetPaintToLayer(true);
+ child_view1->SetFillsBoundsOpaquely(true);
+ child_view1->SetBounds(50, 50, 100, 100);
+ parent_view->AddChildView(child_view1);
+
+ View* child_view2 = new View;
+ child_view2->SetPaintToLayer(true);
+ child_view2->SetFillsBoundsOpaquely(false);
+ child_view2->SetBounds(150, 150, 200, 200);
+ parent_view->AddChildView(child_view2);
+
+ widget()->GetCompositor()->Draw(false);
+
+ // Only child_view1 is opaque
+ EXPECT_EQ(
+ gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect());
+
+ // Both child views are opaque
+ child_view2->SetFillsBoundsOpaquely(true);
+ widget()->GetCompositor()->Draw(false);
+ EXPECT_TRUE(
+ gfx::Rect(50, 50, 100, 100) == parent_view->layer()->hole_rect() ||
+ gfx::Rect(150, 150, 200, 200) == parent_view->layer()->hole_rect());
+
+ // Only child_view2 is opaque
+ delete child_view1;
+ EXPECT_EQ(
+ gfx::Rect(150, 150, 200, 200), parent_view->layer()->hole_rect());
+}
+
+// Makes sure that opacity of layer persists after toggling visibilty.
+TEST_F(ViewLayerTest, ToggleVisibilityWithOpaqueLayer) {
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+ View* parent_view = new View;
+ parent_view->SetPaintToLayer(true);
+ parent_view->SetBounds(0, 0, 400, 400);
+ content_view->AddChildView(parent_view);
+
+ parent_view->SetPaintToLayer(true);
+ parent_view->SetBounds(0, 0, 400, 400);
+
+ View* child_view = new View;
+ child_view->SetBounds(50, 50, 100, 100);
+ child_view->SetPaintToLayer(true);
+ child_view->SetFillsBoundsOpaquely(true);
+ parent_view->AddChildView(child_view);
+ widget()->GetCompositor()->Draw(false);
+ EXPECT_EQ(
+ gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect());
+
+ child_view->SetVisible(false);
+ widget()->GetCompositor()->Draw(false);
+ EXPECT_TRUE(parent_view->layer()->hole_rect().IsEmpty());
+
+ child_view->SetVisible(true);
+ widget()->GetCompositor()->Draw(false);
+ EXPECT_EQ(
+ gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect());
+}
+
+// Tests that the layers in the subtree are orphaned after a View is removed
+// from the parent.
+TEST_F(ViewLayerTest, OrphanLayerAfterViewRemove) {
+ View* content_view = new View;
+ widget()->SetContentsView(content_view);
+
+ View* v1 = new View;
+ content_view->AddChildView(v1);
+
+ View* v2 = new View;
+ v1->AddChildView(v2);
+ v2->SetPaintToLayer(true);
+ EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
+ v2->layer()));
+ EXPECT_TRUE(v2->layer()->IsDrawn());
+
+ content_view->RemoveChildView(v1);
+ EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
+ v2->layer()));
+
+ // Reparent |v2|.
+ content_view->AddChildView(v2);
+ EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
+ v2->layer()));
+ EXPECT_TRUE(v2->layer()->IsDrawn());
+}
+
+class PaintTrackingView : public View {
+ public:
+ PaintTrackingView() : painted_(false) {
+ }
+
+ bool painted() const { return painted_; }
+ void set_painted(bool value) { painted_ = value; }
+
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
+ painted_ = true;
+ }
+
+ private:
+ bool painted_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaintTrackingView);
+};
+
+#if !defined(USE_WEBKIT_COMPOSITOR)
+// TODO(piman): this test relies on the way the non-webkit compositor works.
+// Layer::DrawTree should not be called with the webkit compositor. In the
+// WebKit case, it needs to go through the "real" compositor (not the test one)
+// to do the paints on the layer/views.
+
+// Makes sure child views with layers aren't painted when paint starts at an
+// ancestor.
+TEST_F(ViewLayerTest, DontPaintChildrenWithLayers) {
+ PaintTrackingView* content_view = new PaintTrackingView;
+ widget()->SetContentsView(content_view);
+ content_view->SetPaintToLayer(true);
+ GetRootLayer()->DrawTree();
+ GetRootLayer()->SchedulePaint(gfx::Rect(0, 0, 10, 10));
+ content_view->set_painted(false);
+ // content_view no longer has a dirty rect. Paint from the root and make sure
+ // PaintTrackingView isn't painted.
+ GetRootLayer()->DrawTree();
+ EXPECT_FALSE(content_view->painted());
+
+ // Make content_view have a dirty rect, paint the layers and make sure
+ // PaintTrackingView is painted.
+ content_view->layer()->SchedulePaint(gfx::Rect(0, 0, 10, 10));
+ GetRootLayer()->DrawTree();
+ EXPECT_TRUE(content_view->painted());
+}
+#endif
+
+// Tests that the visibility of child layers are updated correctly when a View's
+// visibility changes.
+TEST_F(ViewLayerTest, VisibilityChildLayers) {
+ View* v1 = new View;
+ v1->SetPaintToLayer(true);
+ widget()->SetContentsView(v1);
+
+ View* v2 = new View;
+ v1->AddChildView(v2);
+
+ View* v3 = new View;
+ v2->AddChildView(v3);
+ v3->SetVisible(false);
+
+ View* v4 = new View;
+ v4->SetPaintToLayer(true);
+ v3->AddChildView(v4);
+
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+ EXPECT_FALSE(v4->layer()->IsDrawn());
+
+ v2->SetVisible(false);
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+ EXPECT_FALSE(v4->layer()->IsDrawn());
+
+ v2->SetVisible(true);
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+ EXPECT_FALSE(v4->layer()->IsDrawn());
+
+ v2->SetVisible(false);
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+ EXPECT_FALSE(v4->layer()->IsDrawn());
+ EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
+
+ v3->SetVisible(true);
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+ EXPECT_FALSE(v4->layer()->IsDrawn());
+ EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
+
+ // Reparent |v3| to |v1|.
+ v1->AddChildView(v3);
+ EXPECT_TRUE(v1->layer()->IsDrawn());
+ EXPECT_TRUE(v4->layer()->IsDrawn());
+ EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
+}
+
+// This test creates a random View tree, and then randomly reorders child views,
+// reparents views etc. Unrelated changes can appear to break this test. So
+// marking this as FLAKY.
+TEST_F(ViewLayerTest, FLAKY_ViewLayerTreesInSync) {
+ View* content = new View;
+ content->SetPaintToLayer(true);
+ widget()->SetContentsView(content);
+ widget()->Show();
+
+ ConstructTree(content, 5);
+ EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
+
+ ScrambleTree(content);
+ EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
+
+ ScrambleTree(content);
+ EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
+
+ ScrambleTree(content);
+ EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
+}
+
+#endif // VIEWS_COMPOSITOR
+
+} // namespace views
diff --git a/ui/views/view_win.cc b/ui/views/view_win.cc
new file mode 100644
index 0000000..472fbcd
--- /dev/null
+++ b/ui/views/view_win.cc
@@ -0,0 +1,36 @@
+// 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/view.h"
+
+// Necessary to define oleacc GUID's.
+#include <windows.h>
+#include <initguid.h>
+#include <oleacc.h>
+
+#include "ui/views/accessibility/native_view_accessibility_win.h"
+
+namespace views {
+
+gfx::NativeViewAccessible View::GetNativeViewAccessible() {
+ if (!native_view_accessibility_win_.get())
+ native_view_accessibility_win_ = NativeViewAccessibilityWin::Create(this);
+ return native_view_accessibility_win_.get();
+}
+
+int View::GetHorizontalDragThreshold() {
+ static int threshold = -1;
+ if (threshold == -1)
+ threshold = GetSystemMetrics(SM_CXDRAG) / 2;
+ return threshold;
+}
+
+int View::GetVerticalDragThreshold() {
+ static int threshold = -1;
+ if (threshold == -1)
+ threshold = GetSystemMetrics(SM_CYDRAG) / 2;
+ return threshold;
+}
+
+} // namespace views
diff --git a/ui/views/widget/drop_helper.cc b/ui/views/widget/drop_helper.cc
index a351090..5b70260 100644
--- a/ui/views/widget/drop_helper.cc
+++ b/ui/views/widget/drop_helper.cc
@@ -5,8 +5,8 @@
#include "ui/views/widget/drop_helper.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/widget/native_widget_test_utils_aura.cc b/ui/views/widget/native_widget_test_utils_aura.cc
index 4b0ecec..af7cf59 100644
--- a/ui/views/widget/native_widget_test_utils_aura.cc
+++ b/ui/views/widget/native_widget_test_utils_aura.cc
@@ -4,9 +4,9 @@
#include "ui/views/widget/native_widget_test_utils.h"
+#include "ui/views/view.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
namespace internal {
diff --git a/ui/views/widget/native_widget_test_utils_gtk.cc b/ui/views/widget/native_widget_test_utils_gtk.cc
index 60c2050..3f3fc76 100644
--- a/ui/views/widget/native_widget_test_utils_gtk.cc
+++ b/ui/views/widget/native_widget_test_utils_gtk.cc
@@ -4,9 +4,9 @@
#include "ui/views/widget/native_widget_test_utils.h"
+#include "ui/views/view.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
namespace internal {
diff --git a/ui/views/widget/native_widget_test_utils_win.cc b/ui/views/widget/native_widget_test_utils_win.cc
index 4b0ecec..af7cf59 100644
--- a/ui/views/widget/native_widget_test_utils_win.cc
+++ b/ui/views/widget/native_widget_test_utils_win.cc
@@ -4,9 +4,9 @@
#include "ui/views/widget/native_widget_test_utils.h"
+#include "ui/views/view.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
namespace internal {
diff --git a/ui/views/widget/native_widget_unittest.cc b/ui/views/widget/native_widget_unittest.cc
index 7e9b4de..808649a 100644
--- a/ui/views/widget/native_widget_unittest.cc
+++ b/ui/views/widget/native_widget_unittest.cc
@@ -5,10 +5,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/native_widget_test_utils.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/widget/root_view.h b/ui/views/widget/root_view.h
index d5df829..0158f7f 100644
--- a/ui/views/widget/root_view.h
+++ b/ui/views/widget/root_view.h
@@ -11,7 +11,7 @@
#include "base/memory/ref_counted.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/focus_search.h"
-#include "views/view.h"
+#include "ui/views/view.h"
namespace ui {
enum TouchStatus;
diff --git a/ui/views/widget/tooltip_manager_gtk.cc b/ui/views/widget/tooltip_manager_gtk.cc
index b33e5ad..8114128 100644
--- a/ui/views/widget/tooltip_manager_gtk.cc
+++ b/ui/views/widget/tooltip_manager_gtk.cc
@@ -9,8 +9,8 @@
#include "ui/gfx/font.h"
#include "ui/gfx/screen.h"
#include "ui/views/focus/focus_manager.h"
+#include "ui/views/view.h"
#include "ui/views/widget/native_widget_gtk.h"
-#include "views/view.h"
// WARNING: this implementation is good for a start, but it doesn't give us
// control of tooltip positioning both on mouse events and when showing from
diff --git a/ui/views/widget/tooltip_manager_views.cc b/ui/views/widget/tooltip_manager_views.cc
index fa3cb63..264dbc3 100644
--- a/ui/views/widget/tooltip_manager_views.cc
+++ b/ui/views/widget/tooltip_manager_views.cc
@@ -28,10 +28,10 @@
#include "ui/gfx/screen.h"
#include "ui/views/events/event.h"
#include "ui/views/focus/focus_manager.h"
+#include "ui/views/view.h"
#include "ui/views/widget/native_widget.h"
#include "views/background.h"
#include "views/border.h"
-#include "views/view.h"
namespace {
SkColor kTooltipBackground = 0xFF7F7F00;
diff --git a/ui/views/widget/tooltip_manager_views.h b/ui/views/widget/tooltip_manager_views.h
index e844ddf..1a6ef18 100644
--- a/ui/views/widget/tooltip_manager_views.h
+++ b/ui/views/widget/tooltip_manager_views.h
@@ -9,10 +9,10 @@
#include "base/message_loop.h"
#include "base/timer.h"
#include "ui/views/controls/label.h"
+#include "ui/views/view.h"
#include "ui/views/widget/native_widget.h"
#include "ui/views/widget/tooltip_manager.h"
#include "ui/views/widget/widget_delegate.h"
-#include "views/view.h"
#if defined(USE_X11)
typedef union _XEvent XEvent;
diff --git a/ui/views/widget/tooltip_manager_win.cc b/ui/views/widget/tooltip_manager_win.cc
index fedb700..f03d858 100644
--- a/ui/views/widget/tooltip_manager_win.cc
+++ b/ui/views/widget/tooltip_manager_win.cc
@@ -17,9 +17,9 @@
#include "ui/base/win/hwnd_util.h"
#include "ui/gfx/font.h"
#include "ui/gfx/screen.h"
+#include "ui/views/view.h"
#include "ui/views/widget/monitor_win.h"
#include "ui/views/widget/widget.h"
-#include "views/view.h"
namespace views {
diff --git a/ui/views/widget/widget_delegate.cc b/ui/views/widget/widget_delegate.cc
index 94ebcf1..84af2343 100644
--- a/ui/views/widget/widget_delegate.cc
+++ b/ui/views/widget/widget_delegate.cc
@@ -7,9 +7,9 @@
#include "base/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/client_view.h"
-#include "views/view.h"
#include "views/views_delegate.h"
namespace views {
diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h
index b771d33..58a2c72 100644
--- a/ui/views/widget/widget_delegate.h
+++ b/ui/views/widget/widget_delegate.h
@@ -11,7 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "ui/base/accessibility/accessibility_types.h"
#include "ui/base/ui_base_types.h"
-#include "views/view.h"
+#include "ui/views/view.h"
class SkBitmap;
diff --git a/ui/views/window/client_view.h b/ui/views/window/client_view.h
index 4b809f2..46da6e2 100644
--- a/ui/views/window/client_view.h
+++ b/ui/views/window/client_view.h
@@ -6,7 +6,7 @@
#define UI_VIEWS_WINDOW_CLIENT_VIEW_H_
#pragma once
-#include "views/view.h"
+#include "ui/views/view.h"
namespace views {
diff --git a/ui/views/window/non_client_view.h b/ui/views/window/non_client_view.h
index fc97d69..eaea2bc 100644
--- a/ui/views/window/non_client_view.h
+++ b/ui/views/window/non_client_view.h
@@ -6,8 +6,8 @@
#define UI_VIEWS_WINDOW_NON_CLIENT_VIEW_H_
#pragma once
+#include "ui/views/view.h"
#include "ui/views/window/client_view.h"
-#include "views/view.h"
namespace gfx {
class Path;