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

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: tab strip problems addressed 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 #else 61 #else
62 bool use_acceleration_when_possible = false; 62 bool use_acceleration_when_possible = false;
63 #endif 63 #endif
64 64
65 #if defined(OS_WIN) 65 #if defined(OS_WIN)
66 const bool kContextMenuOnMousePress = false; 66 const bool kContextMenuOnMousePress = false;
67 #else 67 #else
68 const bool kContextMenuOnMousePress = true; 68 const bool kContextMenuOnMousePress = true;
69 #endif 69 #endif
70 70
71 // The minimum percentage of a view's area that needs to be covered by a rect
72 // representing a touch region in order for that view to be considered by the
73 // views fuzzing algorithm.
74 static const float kViewsFuzzingOverlap = 0.6;
75
71 // Returns the top view in |view|'s hierarchy. 76 // Returns the top view in |view|'s hierarchy.
72 const views::View* GetHierarchyRoot(const views::View* view) { 77 const views::View* GetHierarchyRoot(const views::View* view) {
73 const views::View* root = view; 78 const views::View* root = view;
74 while (root && root->parent()) 79 while (root && root->parent())
75 root = root->parent(); 80 root = root->parent();
76 return root; 81 return root;
77 } 82 }
78 83
79 } // namespace 84 } // namespace
80 85
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after
674 target->ConvertPointFromAncestor(root, point); 679 target->ConvertPointFromAncestor(root, point);
675 680
676 // API defines NULL |source| as returning the point in screen coordinates. 681 // API defines NULL |source| as returning the point in screen coordinates.
677 if (!source) { 682 if (!source) {
678 *point -= 683 *point -=
679 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin(); 684 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin();
680 } 685 }
681 } 686 }
682 687
683 // static 688 // static
689 void View::ConvertRectToTarget(const View* source,
690 const View* target,
691 gfx::Rect* rect) {
692 if (source == target)
693 return;
694
695 // |source| can be NULL.
696 const View* root = GetHierarchyRoot(target);
697 if (source) {
698 CHECK_EQ(GetHierarchyRoot(source), root);
699
700 if (source != root)
701 source->ConvertRectForAncestor(root, rect);
702 }
703
704 if (target != root)
705 target->ConvertRectFromAncestor(root, rect);
706
707 // API defines NULL |source| as returning the point in screen coordinates.
708 if (!source) {
709 rect->set_origin(rect->origin() -
710 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin());
711 }
712 }
713
714 // static
684 void View::ConvertPointToWidget(const View* src, gfx::Point* p) { 715 void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
685 DCHECK(src); 716 DCHECK(src);
686 DCHECK(p); 717 DCHECK(p);
687 718
688 src->ConvertPointForAncestor(NULL, p); 719 src->ConvertPointForAncestor(NULL, p);
689 } 720 }
690 721
691 // static 722 // static
692 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { 723 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
693 DCHECK(dest); 724 DCHECK(dest);
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
800 } 831 }
801 832
802 // static 833 // static
803 bool View::get_use_acceleration_when_possible() { 834 bool View::get_use_acceleration_when_possible() {
804 return use_acceleration_when_possible; 835 return use_acceleration_when_possible;
805 } 836 }
806 837
807 // Input ----------------------------------------------------------------------- 838 // Input -----------------------------------------------------------------------
808 839
809 View* View::GetEventHandlerForPoint(const gfx::Point& point) { 840 View* View::GetEventHandlerForPoint(const gfx::Point& point) {
810 // Walk the child Views recursively looking for the View that most 841 return GetEventHandlerForRect(gfx::Rect(point, gfx::Size(1, 1)));
811 // tightly encloses the specified point. 842 }
843
844 View* View::GetEventHandlerForRect(const gfx::Rect& rect) {
845 // |rect_view| represents the current best candidate to return
846 // if rect-based targeting (i.e., fuzzing) is used.
847 // |rect_view_distance| is used to keep track of the distance
848 // between the center point of |rect_view| and the center
849 // point of |rect|.
850 View* rect_view = NULL;
851 int rect_view_distance = INT_MAX;
852
853 // |point_view| represents the view that would have been returned
854 // from this function call if point-based targeting were used.
855 View* point_view = NULL;
856
812 for (int i = child_count() - 1; i >= 0; --i) { 857 for (int i = child_count() - 1; i >= 0; --i) {
813 View* child = child_at(i); 858 View* child = child_at(i);
859
860 // Ignore any children which are invisible or do not intersect |rect|.
814 if (!child->visible()) 861 if (!child->visible())
815 continue; 862 continue;
863 gfx::Rect rect_in_child_coords(rect);
864 ConvertRectToTarget(this, child, &rect_in_child_coords);
865 if (!child->HitTestRect(rect_in_child_coords))
866 continue;
816 867
817 gfx::Point point_in_child_coords(point); 868 View* cur_view = child->GetEventHandlerForRect(rect_in_child_coords);
818 ConvertPointToTarget(this, child, &point_in_child_coords); 869
819 if (child->HitTestPoint(point_in_child_coords)) 870 if (UsePointBasedTargeting(rect))
820 return child->GetEventHandlerForPoint(point_in_child_coords); 871 return cur_view;
872
873 gfx::Rect cur_rect(cur_view->GetLocalBounds());
sky 2013/10/04 17:03:49 cur_rect -> cur_view_bounds
tdanderson 2013/10/07 21:35:21 Done.
874 ConvertRectToTarget(cur_view, this, &cur_rect);
875 if (PercentCoveredBy(cur_rect, rect) >= kViewsFuzzingOverlap) {
876 // |cur_view| is a suitable candidate for rect-based targeting.
877 // Check to see if it is the closest suitable candidate so far.
878 gfx::Point touch_center(rect.CenterPoint());
879 // Terry: change this to just use distance between center points.
sky 2013/10/04 17:03:49 TODO(tdanderson):
tdanderson 2013/10/07 21:35:21 On second thought, I'm going to leave this as is s
880 int cur_dist = DistanceSquaredFromCenterLineToPoint(touch_center,
881 cur_rect);
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.CenterPoint());
sky 2013/10/04 17:03:49 Can you use the center point of rect_in_child_coor
tdanderson 2013/10/07 21:35:21 Done.
890 ConvertPointToTarget(this, child, &point_in_child_coords);
891 if (child->HitTestPoint(point_in_child_coords))
892 point_view = child->GetEventHandlerForPoint(point_in_child_coords);
893 }
821 } 894 }
822 return this; 895
896 if (UsePointBasedTargeting(rect) || (!rect_view && !point_view))
897 return this;
898
899 return rect_view ? rect_view : point_view;
823 } 900 }
824 901
825 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) { 902 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) {
826 if (!HitTestPoint(point)) 903 if (!HitTestPoint(point))
827 return NULL; 904 return NULL;
828 905
829 // Walk the child Views recursively looking for the View that most 906 // Walk the child Views recursively looking for the View that most
830 // tightly encloses the specified point. 907 // tightly encloses the specified point.
831 for (int i = child_count() - 1; i >= 0; --i) { 908 for (int i = child_count() - 1; i >= 0; --i) {
832 View* child = child_at(i); 909 View* child = child_at(i);
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after
1243 int View::GetPageScrollIncrement(ScrollView* scroll_view, 1320 int View::GetPageScrollIncrement(ScrollView* scroll_view,
1244 bool is_horizontal, bool is_positive) { 1321 bool is_horizontal, bool is_positive) {
1245 return 0; 1322 return 0;
1246 } 1323 }
1247 1324
1248 int View::GetLineScrollIncrement(ScrollView* scroll_view, 1325 int View::GetLineScrollIncrement(ScrollView* scroll_view,
1249 bool is_horizontal, bool is_positive) { 1326 bool is_horizontal, bool is_positive) {
1250 return 0; 1327 return 0;
1251 } 1328 }
1252 1329
1330 // Views fuzzing ---------------------------------------------------------------
1331
1332 // static
1333 bool View::UsePointBasedTargeting(const gfx::Rect& rect) {
1334 return rect.width() == 1 && rect.height() == 1;
1335 }
1336
1337 // static
1338 float View::PercentCoveredBy(const gfx::Rect& rect_1, const gfx::Rect& rect_2) {
1339 gfx::Rect intersection(rect_1);
1340 intersection.Intersect(rect_2);
1341 float intersection_area = intersection.size().GetArea();
sky 2013/10/04 17:03:49 Should this and 1342 be kept as ints and then case
tdanderson 2013/10/07 21:35:21 Done.
1342 float rect_1_area = rect_1.size().GetArea();
1343 return rect_1_area ? intersection_area / rect_1_area : 0;
1344 }
1345
1346 // The positive distance from |pos| to the nearest endpoint of the interval
1347 // [start, end] is returned if |pos| lies within the interval, otherwise
1348 // 0 is returned.
1349 int DistanceToInterval(int pos, int start, int end) {
1350 if (pos < start)
1351 return start - pos;
1352 if (pos > end)
1353 return pos - end;
1354 return 0;
1355 }
1356
1357 // static
1358 int View::DistanceSquaredFromCenterLineToPoint(const gfx::Point& point,
1359 const gfx::Rect& target_rect) {
1360 gfx::Point center_point = target_rect.CenterPoint();
1361 int dx = center_point.x() - point.x();
1362 int dy = center_point.y() - point.y();
1363
1364 if (target_rect.width() > target_rect.height()) {
1365 dx = DistanceToInterval(point.x(),
1366 target_rect.x() + (target_rect.height() / 2),
1367 target_rect.right() - (target_rect.height() / 2));
1368 } else {
1369 dy = DistanceToInterval(point.y(),
1370 target_rect.y() + (target_rect.width() / 2),
1371 target_rect.bottom() - (target_rect.width() / 2));
1372 }
1373 return (dx * dx) + (dy * dy);
1374 }
1375
1253 //////////////////////////////////////////////////////////////////////////////// 1376 ////////////////////////////////////////////////////////////////////////////////
1254 // View, protected: 1377 // View, protected:
1255 1378
1256 // Size and disposition -------------------------------------------------------- 1379 // Size and disposition --------------------------------------------------------
1257 1380
1258 void View::OnBoundsChanged(const gfx::Rect& previous_bounds) { 1381 void View::OnBoundsChanged(const gfx::Rect& previous_bounds) {
1259 } 1382 }
1260 1383
1261 void View::PreferredSizeChanged() { 1384 void View::PreferredSizeChanged() {
1262 InvalidateLayout(); 1385 InvalidateLayout();
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after
1971 bool View::ConvertPointFromAncestor(const View* ancestor, 2094 bool View::ConvertPointFromAncestor(const View* ancestor,
1972 gfx::Point* point) const { 2095 gfx::Point* point) const {
1973 gfx::Transform trans; 2096 gfx::Transform trans;
1974 bool result = GetTransformRelativeTo(ancestor, &trans); 2097 bool result = GetTransformRelativeTo(ancestor, &trans);
1975 gfx::Point3F p(*point); 2098 gfx::Point3F p(*point);
1976 trans.TransformPointReverse(&p); 2099 trans.TransformPointReverse(&p);
1977 *point = gfx::ToFlooredPoint(p.AsPointF()); 2100 *point = gfx::ToFlooredPoint(p.AsPointF());
1978 return result; 2101 return result;
1979 } 2102 }
1980 2103
2104 bool View::ConvertRectForAncestor(const View* ancestor,
2105 gfx::Rect* rect) const {
2106 gfx::Transform trans;
2107 // TODO(sad): Have some way of caching the transformation results.
2108 bool result = GetTransformRelativeTo(ancestor, &trans);
2109 gfx::RectF r(*rect);
2110 trans.TransformRect(&r);
2111 *rect = gfx::ToEnclosingRect(r);
2112 return result;
2113 }
2114
2115 bool View::ConvertRectFromAncestor(const View* ancestor,
2116 gfx::Rect* rect) const {
2117 gfx::Transform trans;
2118 bool result = GetTransformRelativeTo(ancestor, &trans);
2119 gfx::RectF r(*rect);
2120 trans.TransformRectReverse(&r);
2121 *rect = gfx::ToEnclosingRect(r);
2122 return result;
2123 }
2124
1981 // Accelerated painting -------------------------------------------------------- 2125 // Accelerated painting --------------------------------------------------------
1982 2126
1983 void View::CreateLayer() { 2127 void View::CreateLayer() {
1984 // A new layer is being created for the view. So all the layers of the 2128 // 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. 2129 // sub-tree can inherit the visibility of the corresponding view.
1986 for (int i = 0, count = child_count(); i < count; ++i) 2130 for (int i = 0, count = child_count(); i < count; ++i)
1987 child_at(i)->UpdateChildLayerVisibility(true); 2131 child_at(i)->UpdateChildLayerVisibility(true);
1988 2132
1989 layer_ = new ui::Layer(); 2133 layer_ = new ui::Layer();
1990 layer_owner_.reset(layer_); 2134 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 2424 // 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. 2425 // the RootView can detect it and avoid calling us back.
2282 gfx::Point widget_location(event.location()); 2426 gfx::Point widget_location(event.location());
2283 ConvertPointToWidget(this, &widget_location); 2427 ConvertPointToWidget(this, &widget_location);
2284 widget->RunShellDrag(this, data, widget_location, drag_operations, source); 2428 widget->RunShellDrag(this, data, widget_location, drag_operations, source);
2285 // WARNING: we may have been deleted. 2429 // WARNING: we may have been deleted.
2286 return true; 2430 return true;
2287 } 2431 }
2288 2432
2289 } // namespace views 2433 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698