Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: ui/views/view.cc

Issue 22891016: Add support for rect-based event targeting in views (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments addressed, moved fuzzing utility functions to new file Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 20 matching lines...) Expand all
31 #include "ui/gfx/scoped_canvas.h" 31 #include "ui/gfx/scoped_canvas.h"
32 #include "ui/gfx/screen.h" 32 #include "ui/gfx/screen.h"
33 #include "ui/gfx/skia_util.h" 33 #include "ui/gfx/skia_util.h"
34 #include "ui/gfx/transform.h" 34 #include "ui/gfx/transform.h"
35 #include "ui/native_theme/native_theme.h" 35 #include "ui/native_theme/native_theme.h"
36 #include "ui/views/accessibility/native_view_accessibility.h" 36 #include "ui/views/accessibility/native_view_accessibility.h"
37 #include "ui/views/background.h" 37 #include "ui/views/background.h"
38 #include "ui/views/context_menu_controller.h" 38 #include "ui/views/context_menu_controller.h"
39 #include "ui/views/drag_controller.h" 39 #include "ui/views/drag_controller.h"
40 #include "ui/views/layout/layout_manager.h" 40 #include "ui/views/layout/layout_manager.h"
41 #include "ui/views/rect_based_targeting_utils.h"
41 #include "ui/views/views_delegate.h" 42 #include "ui/views/views_delegate.h"
42 #include "ui/views/widget/native_widget_private.h" 43 #include "ui/views/widget/native_widget_private.h"
43 #include "ui/views/widget/root_view.h" 44 #include "ui/views/widget/root_view.h"
44 #include "ui/views/widget/tooltip_manager.h" 45 #include "ui/views/widget/tooltip_manager.h"
45 #include "ui/views/widget/widget.h" 46 #include "ui/views/widget/widget.h"
46 47
47 #if defined(USE_AURA) 48 #if defined(USE_AURA)
48 #include "ui/base/cursor/cursor.h" 49 #include "ui/base/cursor/cursor.h"
49 #endif 50 #endif
50 51
(...skipping 10 matching lines...) Expand all
61 #else 62 #else
62 bool use_acceleration_when_possible = false; 63 bool use_acceleration_when_possible = false;
63 #endif 64 #endif
64 65
65 #if defined(OS_WIN) 66 #if defined(OS_WIN)
66 const bool kContextMenuOnMousePress = false; 67 const bool kContextMenuOnMousePress = false;
67 #else 68 #else
68 const bool kContextMenuOnMousePress = true; 69 const bool kContextMenuOnMousePress = true;
69 #endif 70 #endif
70 71
72 // The minimum percentage of a view's area that needs to be covered by a rect
73 // representing a touch region in order for that view to be considered by the
74 // rect-based targeting algorithm.
75 static const float kRectTargetOverlap = 0.6;
76
71 // Returns the top view in |view|'s hierarchy. 77 // Returns the top view in |view|'s hierarchy.
72 const views::View* GetHierarchyRoot(const views::View* view) { 78 const views::View* GetHierarchyRoot(const views::View* view) {
73 const views::View* root = view; 79 const views::View* root = view;
74 while (root && root->parent()) 80 while (root && root->parent())
75 root = root->parent(); 81 root = root->parent();
76 return root; 82 return root;
77 } 83 }
78 84
79 } // namespace 85 } // namespace
80 86
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after
674 target->ConvertPointFromAncestor(root, point); 680 target->ConvertPointFromAncestor(root, point);
675 681
676 // API defines NULL |source| as returning the point in screen coordinates. 682 // API defines NULL |source| as returning the point in screen coordinates.
677 if (!source) { 683 if (!source) {
678 *point -= 684 *point -=
679 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin(); 685 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin();
680 } 686 }
681 } 687 }
682 688
683 // static 689 // static
690 void View::ConvertRectToTarget(const View* source,
691 const View* target,
692 gfx::Rect* rect) {
693 if (source == target)
694 return;
695
696 // |source| can be NULL.
697 const View* root = GetHierarchyRoot(target);
698 if (source) {
699 CHECK_EQ(GetHierarchyRoot(source), root);
700
701 if (source != root)
702 source->ConvertRectForAncestor(root, rect);
703 }
704
705 if (target != root)
706 target->ConvertRectFromAncestor(root, rect);
707
708 // API defines NULL |source| as returning the point in screen coordinates.
709 if (!source) {
710 rect->set_origin(rect->origin() -
711 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin());
712 }
713 }
714
715 // static
684 void View::ConvertPointToWidget(const View* src, gfx::Point* p) { 716 void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
685 DCHECK(src); 717 DCHECK(src);
686 DCHECK(p); 718 DCHECK(p);
687 719
688 src->ConvertPointForAncestor(NULL, p); 720 src->ConvertPointForAncestor(NULL, p);
689 } 721 }
690 722
691 // static 723 // static
692 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { 724 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
693 DCHECK(dest); 725 DCHECK(dest);
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
800 } 832 }
801 833
802 // static 834 // static
803 bool View::get_use_acceleration_when_possible() { 835 bool View::get_use_acceleration_when_possible() {
804 return use_acceleration_when_possible; 836 return use_acceleration_when_possible;
805 } 837 }
806 838
807 // Input ----------------------------------------------------------------------- 839 // Input -----------------------------------------------------------------------
808 840
809 View* View::GetEventHandlerForPoint(const gfx::Point& point) { 841 View* View::GetEventHandlerForPoint(const gfx::Point& point) {
810 // Walk the child Views recursively looking for the View that most 842 return GetEventHandlerForRect(gfx::Rect(point, gfx::Size(1, 1)));
811 // tightly encloses the specified point. 843 }
844
845 View* View::GetEventHandlerForRect(const gfx::Rect& rect) {
846 // |rect_view| represents the current best candidate to return
847 // if rect-based targeting (i.e., fuzzing) is used.
848 // |rect_view_distance| is used to keep track of the distance
849 // between the center point of |rect_view| and the center
850 // point of |rect|.
851 View* rect_view = NULL;
852 int rect_view_distance = INT_MAX;
853
854 // |point_view| represents the view that would have been returned
855 // from this function call if point-based targeting were used.
856 View* point_view = NULL;
857
812 for (int i = child_count() - 1; i >= 0; --i) { 858 for (int i = child_count() - 1; i >= 0; --i) {
813 View* child = child_at(i); 859 View* child = child_at(i);
860
861 // Ignore any children which are invisible or do not intersect |rect|.
814 if (!child->visible()) 862 if (!child->visible())
815 continue; 863 continue;
864 gfx::Rect rect_in_child_coords(rect);
865 ConvertRectToTarget(this, child, &rect_in_child_coords);
866 if (!child->HitTestRect(rect_in_child_coords))
867 continue;
816 868
817 gfx::Point point_in_child_coords(point); 869 View* cur_view = child->GetEventHandlerForRect(rect_in_child_coords);
818 ConvertPointToTarget(this, child, &point_in_child_coords); 870
819 if (child->HitTestPoint(point_in_child_coords)) 871 if (views::UsePointBasedTargeting(rect))
820 return child->GetEventHandlerForPoint(point_in_child_coords); 872 return cur_view;
873
874 gfx::Rect cur_view_bounds(cur_view->GetLocalBounds());
875 ConvertRectToTarget(cur_view, this, &cur_view_bounds);
876 if (views::PercentCoveredBy(cur_view_bounds, rect) >= kRectTargetOverlap) {
877 // |cur_view| is a suitable candidate for rect-based targeting.
878 // Check to see if it is the closest suitable candidate so far.
879 gfx::Point touch_center(rect.CenterPoint());
880 int cur_dist = views::DistanceSquaredFromCenterLineToPoint(
881 touch_center, cur_view_bounds);
882 if (!rect_view || cur_dist < rect_view_distance) {
883 rect_view = cur_view;
884 rect_view_distance = cur_dist;
885 }
886 } else if (!rect_view && !point_view) {
887 // Rect-based targeting has not yielded any candidates so far. Check
888 // if point-based targeting would have selected |cur_view|.
889 gfx::Point point_in_child_coords(rect_in_child_coords.CenterPoint());
890 if (child->HitTestPoint(point_in_child_coords))
891 point_view = child->GetEventHandlerForPoint(point_in_child_coords);
892 }
821 } 893 }
822 return this; 894
895 if (views::UsePointBasedTargeting(rect) || (!rect_view && !point_view))
896 return this;
897
898 return rect_view ? rect_view : point_view;
823 } 899 }
824 900
825 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) { 901 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) {
826 if (!HitTestPoint(point)) 902 if (!HitTestPoint(point))
827 return NULL; 903 return NULL;
828 904
829 // Walk the child Views recursively looking for the View that most 905 // Walk the child Views recursively looking for the View that most
830 // tightly encloses the specified point. 906 // tightly encloses the specified point.
831 for (int i = child_count() - 1; i >= 0; --i) { 907 for (int i = child_count() - 1; i >= 0; --i) {
832 View* child = child_at(i); 908 View* child = child_at(i);
(...skipping 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after
1971 bool View::ConvertPointFromAncestor(const View* ancestor, 2047 bool View::ConvertPointFromAncestor(const View* ancestor,
1972 gfx::Point* point) const { 2048 gfx::Point* point) const {
1973 gfx::Transform trans; 2049 gfx::Transform trans;
1974 bool result = GetTransformRelativeTo(ancestor, &trans); 2050 bool result = GetTransformRelativeTo(ancestor, &trans);
1975 gfx::Point3F p(*point); 2051 gfx::Point3F p(*point);
1976 trans.TransformPointReverse(&p); 2052 trans.TransformPointReverse(&p);
1977 *point = gfx::ToFlooredPoint(p.AsPointF()); 2053 *point = gfx::ToFlooredPoint(p.AsPointF());
1978 return result; 2054 return result;
1979 } 2055 }
1980 2056
2057 bool View::ConvertRectForAncestor(const View* ancestor,
2058 gfx::Rect* rect) const {
2059 gfx::Transform trans;
2060 // TODO(sad): Have some way of caching the transformation results.
2061 bool result = GetTransformRelativeTo(ancestor, &trans);
2062 gfx::RectF r(*rect);
2063 trans.TransformRect(&r);
2064 *rect = gfx::ToEnclosingRect(r);
2065 return result;
2066 }
2067
2068 bool View::ConvertRectFromAncestor(const View* ancestor,
2069 gfx::Rect* rect) const {
2070 gfx::Transform trans;
2071 bool result = GetTransformRelativeTo(ancestor, &trans);
2072 gfx::RectF r(*rect);
2073 trans.TransformRectReverse(&r);
2074 *rect = gfx::ToEnclosingRect(r);
2075 return result;
2076 }
2077
1981 // Accelerated painting -------------------------------------------------------- 2078 // Accelerated painting --------------------------------------------------------
1982 2079
1983 void View::CreateLayer() { 2080 void View::CreateLayer() {
1984 // A new layer is being created for the view. So all the layers of the 2081 // A new layer is being created for the view. So all the layers of the
1985 // sub-tree can inherit the visibility of the corresponding view. 2082 // sub-tree can inherit the visibility of the corresponding view.
1986 for (int i = 0, count = child_count(); i < count; ++i) 2083 for (int i = 0, count = child_count(); i < count; ++i)
1987 child_at(i)->UpdateChildLayerVisibility(true); 2084 child_at(i)->UpdateChildLayerVisibility(true);
1988 2085
1989 layer_ = new ui::Layer(); 2086 layer_ = new ui::Layer();
1990 layer_owner_.reset(layer_); 2087 layer_owner_.reset(layer_);
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
2280 // Message the RootView to do the drag and drop. That way if we're removed 2377 // Message the RootView to do the drag and drop. That way if we're removed
2281 // the RootView can detect it and avoid calling us back. 2378 // the RootView can detect it and avoid calling us back.
2282 gfx::Point widget_location(event.location()); 2379 gfx::Point widget_location(event.location());
2283 ConvertPointToWidget(this, &widget_location); 2380 ConvertPointToWidget(this, &widget_location);
2284 widget->RunShellDrag(this, data, widget_location, drag_operations, source); 2381 widget->RunShellDrag(this, data, widget_location, drag_operations, source);
2285 // WARNING: we may have been deleted. 2382 // WARNING: we may have been deleted.
2286 return true; 2383 return true;
2287 } 2384 }
2288 2385
2289 } // namespace views 2386 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698