OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #define _USE_MATH_DEFINES // For VC++ to get M_PI. This has to be first. | 5 #define _USE_MATH_DEFINES // For VC++ to get M_PI. This has to be first. |
6 | 6 |
7 #include "ui/views/view.h" | 7 #include "ui/views/view.h" |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "ui/compositor/compositor.h" | 22 #include "ui/compositor/compositor.h" |
23 #include "ui/compositor/dip_util.h" | 23 #include "ui/compositor/dip_util.h" |
24 #include "ui/compositor/layer.h" | 24 #include "ui/compositor/layer.h" |
25 #include "ui/compositor/layer_animator.h" | 25 #include "ui/compositor/layer_animator.h" |
26 #include "ui/events/event_target_iterator.h" | 26 #include "ui/events/event_target_iterator.h" |
27 #include "ui/gfx/canvas.h" | 27 #include "ui/gfx/canvas.h" |
28 #include "ui/gfx/interpolated_transform.h" | 28 #include "ui/gfx/interpolated_transform.h" |
29 #include "ui/gfx/path.h" | 29 #include "ui/gfx/path.h" |
30 #include "ui/gfx/point3_f.h" | 30 #include "ui/gfx/point3_f.h" |
31 #include "ui/gfx/point_conversions.h" | 31 #include "ui/gfx/point_conversions.h" |
32 #include "ui/gfx/rect_conversions.h" | |
33 #include "ui/gfx/scoped_canvas.h" | 32 #include "ui/gfx/scoped_canvas.h" |
34 #include "ui/gfx/screen.h" | 33 #include "ui/gfx/screen.h" |
35 #include "ui/gfx/skia_util.h" | 34 #include "ui/gfx/skia_util.h" |
36 #include "ui/gfx/transform.h" | 35 #include "ui/gfx/transform.h" |
37 #include "ui/native_theme/native_theme.h" | 36 #include "ui/native_theme/native_theme.h" |
38 #include "ui/views/accessibility/native_view_accessibility.h" | 37 #include "ui/views/accessibility/native_view_accessibility.h" |
39 #include "ui/views/background.h" | 38 #include "ui/views/background.h" |
40 #include "ui/views/border.h" | 39 #include "ui/views/border.h" |
41 #include "ui/views/context_menu_controller.h" | 40 #include "ui/views/context_menu_controller.h" |
42 #include "ui/views/drag_controller.h" | 41 #include "ui/views/drag_controller.h" |
43 #include "ui/views/focus/view_storage.h" | 42 #include "ui/views/focus/view_storage.h" |
44 #include "ui/views/layout/layout_manager.h" | 43 #include "ui/views/layout/layout_manager.h" |
45 #include "ui/views/rect_based_targeting_utils.h" | |
46 #include "ui/views/views_delegate.h" | 44 #include "ui/views/views_delegate.h" |
47 #include "ui/views/widget/native_widget_private.h" | 45 #include "ui/views/widget/native_widget_private.h" |
48 #include "ui/views/widget/root_view.h" | 46 #include "ui/views/widget/root_view.h" |
49 #include "ui/views/widget/tooltip_manager.h" | 47 #include "ui/views/widget/tooltip_manager.h" |
50 #include "ui/views/widget/widget.h" | 48 #include "ui/views/widget/widget.h" |
51 | 49 |
52 #if defined(OS_WIN) | 50 #if defined(OS_WIN) |
53 #include "base/win/scoped_gdi_object.h" | 51 #include "base/win/scoped_gdi_object.h" |
54 #endif | 52 #endif |
55 | 53 |
56 namespace { | 54 namespace { |
57 | 55 |
58 #if defined(OS_WIN) | 56 #if defined(OS_WIN) |
59 const bool kContextMenuOnMousePress = false; | 57 const bool kContextMenuOnMousePress = false; |
60 #else | 58 #else |
61 const bool kContextMenuOnMousePress = true; | 59 const bool kContextMenuOnMousePress = true; |
62 #endif | 60 #endif |
63 | 61 |
64 // The minimum percentage of a view's area that needs to be covered by a rect | |
65 // representing a touch region in order for that view to be considered by the | |
66 // rect-based targeting algorithm. | |
67 static const float kRectTargetOverlap = 0.6f; | |
68 | |
69 // Default horizontal drag threshold in pixels. | 62 // Default horizontal drag threshold in pixels. |
70 // Same as what gtk uses. | 63 // Same as what gtk uses. |
71 const int kDefaultHorizontalDragThreshold = 8; | 64 const int kDefaultHorizontalDragThreshold = 8; |
72 | 65 |
73 // Default vertical drag threshold in pixels. | 66 // Default vertical drag threshold in pixels. |
74 // Same as what gtk uses. | 67 // Same as what gtk uses. |
75 const int kDefaultVerticalDragThreshold = 8; | 68 const int kDefaultVerticalDragThreshold = 8; |
76 | 69 |
77 // Returns the top view in |view|'s hierarchy. | 70 // Returns the top view in |view|'s hierarchy. |
78 const views::View* GetHierarchyRoot(const views::View* view) { | 71 const views::View* GetHierarchyRoot(const views::View* view) { |
(...skipping 764 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
843 return widget ? widget->GetNativeTheme() : ui::NativeTheme::instance(); | 836 return widget ? widget->GetNativeTheme() : ui::NativeTheme::instance(); |
844 } | 837 } |
845 | 838 |
846 // Input ----------------------------------------------------------------------- | 839 // Input ----------------------------------------------------------------------- |
847 | 840 |
848 View* View::GetEventHandlerForPoint(const gfx::Point& point) { | 841 View* View::GetEventHandlerForPoint(const gfx::Point& point) { |
849 return GetEventHandlerForRect(gfx::Rect(point, gfx::Size(1, 1))); | 842 return GetEventHandlerForRect(gfx::Rect(point, gfx::Size(1, 1))); |
850 } | 843 } |
851 | 844 |
852 View* View::GetEventHandlerForRect(const gfx::Rect& rect) { | 845 View* View::GetEventHandlerForRect(const gfx::Rect& rect) { |
853 // |rect_view| represents the current best candidate to return | 846 return GetEffectiveViewTargeter()->TargetForRect(this, rect); |
854 // if rect-based targeting (i.e., fuzzing) is used. | |
855 // |rect_view_distance| is used to keep track of the distance | |
856 // between the center point of |rect_view| and the center | |
857 // point of |rect|. | |
858 View* rect_view = NULL; | |
859 int rect_view_distance = INT_MAX; | |
860 | |
861 // |point_view| represents the view that would have been returned | |
862 // from this function call if point-based targeting were used. | |
863 View* point_view = NULL; | |
864 | |
865 for (int i = child_count() - 1; i >= 0; --i) { | |
866 View* child = child_at(i); | |
867 | |
868 if (!child->CanProcessEventsWithinSubtree()) | |
869 continue; | |
870 | |
871 // Ignore any children which are invisible or do not intersect |rect|. | |
872 if (!child->visible()) | |
873 continue; | |
874 gfx::RectF rect_in_child_coords_f(rect); | |
875 ConvertRectToTarget(this, child, &rect_in_child_coords_f); | |
876 gfx::Rect rect_in_child_coords = gfx::ToEnclosingRect( | |
877 rect_in_child_coords_f); | |
878 if (!child->HitTestRect(rect_in_child_coords)) | |
879 continue; | |
880 | |
881 View* cur_view = child->GetEventHandlerForRect(rect_in_child_coords); | |
882 | |
883 if (views::UsePointBasedTargeting(rect)) | |
884 return cur_view; | |
885 | |
886 gfx::RectF cur_view_bounds_f(cur_view->GetLocalBounds()); | |
887 ConvertRectToTarget(cur_view, this, &cur_view_bounds_f); | |
888 gfx::Rect cur_view_bounds = gfx::ToEnclosingRect( | |
889 cur_view_bounds_f); | |
890 if (views::PercentCoveredBy(cur_view_bounds, rect) >= kRectTargetOverlap) { | |
891 // |cur_view| is a suitable candidate for rect-based targeting. | |
892 // Check to see if it is the closest suitable candidate so far. | |
893 gfx::Point touch_center(rect.CenterPoint()); | |
894 int cur_dist = views::DistanceSquaredFromCenterToPoint(touch_center, | |
895 cur_view_bounds); | |
896 if (!rect_view || cur_dist < rect_view_distance) { | |
897 rect_view = cur_view; | |
898 rect_view_distance = cur_dist; | |
899 } | |
900 } else if (!rect_view && !point_view) { | |
901 // Rect-based targeting has not yielded any candidates so far. Check | |
902 // if point-based targeting would have selected |cur_view|. | |
903 gfx::Point point_in_child_coords(rect_in_child_coords.CenterPoint()); | |
904 if (child->HitTestPoint(point_in_child_coords)) | |
905 point_view = child->GetEventHandlerForPoint(point_in_child_coords); | |
906 } | |
907 } | |
908 | |
909 if (views::UsePointBasedTargeting(rect) || (!rect_view && !point_view)) | |
910 return this; | |
911 | |
912 // If |this| is a suitable candidate for rect-based targeting, check to | |
913 // see if it is closer than the current best suitable candidate so far. | |
914 gfx::Rect local_bounds(GetLocalBounds()); | |
915 if (views::PercentCoveredBy(local_bounds, rect) >= kRectTargetOverlap) { | |
916 gfx::Point touch_center(rect.CenterPoint()); | |
917 int cur_dist = views::DistanceSquaredFromCenterToPoint(touch_center, | |
918 local_bounds); | |
919 if (!rect_view || cur_dist < rect_view_distance) | |
920 rect_view = this; | |
921 } | |
922 | |
923 return rect_view ? rect_view : point_view; | |
924 } | 847 } |
925 | 848 |
926 bool View::CanProcessEventsWithinSubtree() const { | 849 bool View::CanProcessEventsWithinSubtree() const { |
927 return true; | 850 return true; |
928 } | 851 } |
929 | 852 |
930 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) { | 853 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) { |
| 854 // TODO(tdanderson): Move this implementation into ViewTargetDelegate. |
931 if (!HitTestPoint(point) || !CanProcessEventsWithinSubtree()) | 855 if (!HitTestPoint(point) || !CanProcessEventsWithinSubtree()) |
932 return NULL; | 856 return NULL; |
933 | 857 |
934 // Walk the child Views recursively looking for the View that most | 858 // Walk the child Views recursively looking for the View that most |
935 // tightly encloses the specified point. | 859 // tightly encloses the specified point. |
936 for (int i = child_count() - 1; i >= 0; --i) { | 860 for (int i = child_count() - 1; i >= 0; --i) { |
937 View* child = child_at(i); | 861 View* child = child_at(i); |
938 if (!child->visible()) | 862 if (!child->visible()) |
939 continue; | 863 continue; |
940 | 864 |
(...skipping 15 matching lines...) Expand all Loading... |
956 #else | 880 #else |
957 return gfx::kNullCursor; | 881 return gfx::kNullCursor; |
958 #endif | 882 #endif |
959 } | 883 } |
960 | 884 |
961 bool View::HitTestPoint(const gfx::Point& point) const { | 885 bool View::HitTestPoint(const gfx::Point& point) const { |
962 return HitTestRect(gfx::Rect(point, gfx::Size(1, 1))); | 886 return HitTestRect(gfx::Rect(point, gfx::Size(1, 1))); |
963 } | 887 } |
964 | 888 |
965 bool View::HitTestRect(const gfx::Rect& rect) const { | 889 bool View::HitTestRect(const gfx::Rect& rect) const { |
966 ViewTargeter* view_targeter = targeter(); | 890 return GetEffectiveViewTargeter()->DoesIntersectRect(this, rect); |
967 if (!view_targeter) | |
968 view_targeter = GetWidget()->GetRootView()->targeter(); | |
969 CHECK(view_targeter); | |
970 return view_targeter->DoesIntersectRect(this, rect); | |
971 } | 891 } |
972 | 892 |
973 bool View::IsMouseHovered() { | 893 bool View::IsMouseHovered() { |
974 // If we haven't yet been placed in an onscreen view hierarchy, we can't be | 894 // If we haven't yet been placed in an onscreen view hierarchy, we can't be |
975 // hovered. | 895 // hovered. |
976 if (!GetWidget()) | 896 if (!GetWidget()) |
977 return false; | 897 return false; |
978 | 898 |
979 // If mouse events are disabled, then the mouse cursor is invisible and | 899 // If mouse events are disabled, then the mouse cursor is invisible and |
980 // is therefore not hovering over this button. | 900 // is therefore not hovering over this button. |
(...skipping 1362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2343 if (HitTestPoint(location)) { | 2263 if (HitTestPoint(location)) { |
2344 ConvertPointToScreen(this, &location); | 2264 ConvertPointToScreen(this, &location); |
2345 ShowContextMenu(location, ui::MENU_SOURCE_MOUSE); | 2265 ShowContextMenu(location, ui::MENU_SOURCE_MOUSE); |
2346 } | 2266 } |
2347 } else { | 2267 } else { |
2348 OnMouseReleased(event); | 2268 OnMouseReleased(event); |
2349 } | 2269 } |
2350 // WARNING: we may have been deleted. | 2270 // WARNING: we may have been deleted. |
2351 } | 2271 } |
2352 | 2272 |
| 2273 ViewTargeter* View::GetEffectiveViewTargeter() const { |
| 2274 ViewTargeter* view_targeter = targeter(); |
| 2275 if (!view_targeter) |
| 2276 view_targeter = GetWidget()->GetRootView()->targeter(); |
| 2277 CHECK(view_targeter); |
| 2278 return view_targeter; |
| 2279 } |
| 2280 |
2353 // Accelerators ---------------------------------------------------------------- | 2281 // Accelerators ---------------------------------------------------------------- |
2354 | 2282 |
2355 void View::RegisterPendingAccelerators() { | 2283 void View::RegisterPendingAccelerators() { |
2356 if (!accelerators_.get() || | 2284 if (!accelerators_.get() || |
2357 registered_accelerator_count_ == accelerators_->size()) { | 2285 registered_accelerator_count_ == accelerators_->size()) { |
2358 // No accelerators are waiting for registration. | 2286 // No accelerators are waiting for registration. |
2359 return; | 2287 return; |
2360 } | 2288 } |
2361 | 2289 |
2362 if (!GetWidget()) { | 2290 if (!GetWidget()) { |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2492 // Message the RootView to do the drag and drop. That way if we're removed | 2420 // Message the RootView to do the drag and drop. That way if we're removed |
2493 // the RootView can detect it and avoid calling us back. | 2421 // the RootView can detect it and avoid calling us back. |
2494 gfx::Point widget_location(event.location()); | 2422 gfx::Point widget_location(event.location()); |
2495 ConvertPointToWidget(this, &widget_location); | 2423 ConvertPointToWidget(this, &widget_location); |
2496 widget->RunShellDrag(this, data, widget_location, drag_operations, source); | 2424 widget->RunShellDrag(this, data, widget_location, drag_operations, source); |
2497 // WARNING: we may have been deleted. | 2425 // WARNING: we may have been deleted. |
2498 return true; | 2426 return true; |
2499 } | 2427 } |
2500 | 2428 |
2501 } // namespace views | 2429 } // namespace views |
OLD | NEW |