| 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 |