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

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: WIP Created 7 years, 3 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 #else 56 #else
57 bool use_acceleration_when_possible = false; 57 bool use_acceleration_when_possible = false;
58 #endif 58 #endif
59 59
60 #if defined(OS_WIN) 60 #if defined(OS_WIN)
61 const bool kContextMenuOnMousePress = false; 61 const bool kContextMenuOnMousePress = false;
62 #else 62 #else
63 const bool kContextMenuOnMousePress = true; 63 const bool kContextMenuOnMousePress = true;
64 #endif 64 #endif
65 65
66 // The minimum percentage of a view's area that needs to be covered by a rect
67 // representing a touch region in order for that view to be considered by the
68 // views fuzzing algorithm.
69 static const float kViewsFuzzingOverlap = 0.6;
70
66 // Saves the drawing state, and restores the state when going out of scope. 71 // Saves the drawing state, and restores the state when going out of scope.
67 class ScopedCanvas { 72 class ScopedCanvas {
68 public: 73 public:
69 explicit ScopedCanvas(gfx::Canvas* canvas) : canvas_(canvas) { 74 explicit ScopedCanvas(gfx::Canvas* canvas) : canvas_(canvas) {
70 if (canvas_) 75 if (canvas_)
71 canvas_->Save(); 76 canvas_->Save();
72 } 77 }
73 ~ScopedCanvas() { 78 ~ScopedCanvas() {
74 if (canvas_) 79 if (canvas_)
75 canvas_->Restore(); 80 canvas_->Restore();
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after
693 target->ConvertPointFromAncestor(root, point); 698 target->ConvertPointFromAncestor(root, point);
694 699
695 // API defines NULL |source| as returning the point in screen coordinates. 700 // API defines NULL |source| as returning the point in screen coordinates.
696 if (!source) { 701 if (!source) {
697 *point -= 702 *point -=
698 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin(); 703 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin();
699 } 704 }
700 } 705 }
701 706
702 // static 707 // static
708 void View::ConvertRectToTarget(const View* source,
709 const View* target,
710 gfx::Rect* rect) {
711 if (source == target)
712 return;
713
714 // |source| can be NULL.
715 const View* root = GetHierarchyRoot(target);
716 if (source) {
717 CHECK_EQ(GetHierarchyRoot(source), root);
718
719 if (source != root)
720 source->ConvertRectForAncestor(root, rect);
721 }
722
723 if (target != root)
724 target->ConvertRectFromAncestor(root, rect);
725
726 // API defines NULL |source| as returning the point in screen coordinates.
727 if (!source) {
728 rect->set_origin(rect->origin() -
729 root->GetWidget()->GetClientAreaBoundsInScreen().OffsetFromOrigin());
730 }
731 }
732
733 // static
703 void View::ConvertPointToWidget(const View* src, gfx::Point* p) { 734 void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
704 DCHECK(src); 735 DCHECK(src);
705 DCHECK(p); 736 DCHECK(p);
706 737
707 src->ConvertPointForAncestor(NULL, p); 738 src->ConvertPointForAncestor(NULL, p);
708 } 739 }
709 740
710 // static 741 // static
711 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { 742 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
712 DCHECK(dest); 743 DCHECK(dest);
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
818 use_acceleration_when_possible = use; 849 use_acceleration_when_possible = use;
819 } 850 }
820 851
821 // static 852 // static
822 bool View::get_use_acceleration_when_possible() { 853 bool View::get_use_acceleration_when_possible() {
823 return use_acceleration_when_possible; 854 return use_acceleration_when_possible;
824 } 855 }
825 856
826 // Input ----------------------------------------------------------------------- 857 // Input -----------------------------------------------------------------------
827 858
828 View* View::GetEventHandlerForPoint(const gfx::Point& point) { 859 View* View::GetEventHandlerForPoint(const gfx::Point& point) {
sky 2013/09/06 19:56:47 Is there a reason to keep this? Keep it is error p
tdanderson 2013/09/09 22:15:39 I am keeping it as a convenience so that existing
829 // Walk the child Views recursively looking for the View that most 860 return GetEventHandlerForRect(gfx::Rect(point, gfx::Size(1, 1)));
830 // tightly encloses the specified point. 861 }
862
863 View* View::GetEventHandlerForRect(const gfx::Rect& rect) {
sky 2013/09/06 19:56:47 I kind of think the return value should be changed
tdanderson 2013/09/09 22:15:39 Please see my reply to your comment at line 897.
864 // |rect_view| represents the current best candidate to return
865 // if rect-based targeting (i.e., fuzzing) is used.
866 // |rect_view_distance| is used to keep track of the distance
867 // between the center point of |rect_view| and the center
868 // point of |rect|.
869 View* rect_view = NULL;
870 int rect_view_distance = INT_MAX;
871
872 // |point_view| represents the view that would have been returned
873 // from this function call if point-based targeting were used.
874 View* point_view = NULL;
875
831 for (int i = child_count() - 1; i >= 0; --i) { 876 for (int i = child_count() - 1; i >= 0; --i) {
832 View* child = child_at(i); 877 View* child = child_at(i);
878
879 // Ignore any children which are invisible or do not intersect |rect|.
833 if (!child->visible()) 880 if (!child->visible())
834 continue; 881 continue;
882 gfx::Rect rect_in_child_coords(rect);
883 ConvertRectToTarget(this, child, &rect_in_child_coords);
884 if (!child->HitTestRect(rect_in_child_coords))
885 continue;
835 886
836 gfx::Point point_in_child_coords(point); 887 View* cur_view = child->GetEventHandlerForRect(rect_in_child_coords);
837 ConvertPointToTarget(this, child, &point_in_child_coords); 888
838 if (child->HitTestPoint(point_in_child_coords)) 889 if (UsePointBasedTargeting(rect))
839 return child->GetEventHandlerForPoint(point_in_child_coords); 890 return cur_view;
891
892 gfx::Rect cur_rect(cur_view->GetLocalBounds());
893 ConvertRectToTarget(cur_view, this, &cur_rect);
894 if (PercentCoveredBy(cur_rect, rect) >= kViewsFuzzingOverlap) {
sky 2013/09/06 19:56:47 Doesn't this assume the view completely fills its
tdanderson 2013/09/09 22:15:39 Yes, good point... I am going to try and use the h
895 // |cur_view| is a suitable candidate for rect-based targeting.
896 // Check to see if it is the closest suitable candidate so far.
897 gfx::Point touch_center(rect.CenterPoint());
sky 2013/09/06 19:56:47 Can't you return some where in here if the view co
tdanderson 2013/09/09 22:15:39 I don't think an early return is possible by just
sky 2013/09/10 16:47:41 99% of the views don't allow overlapping children,
898 // Terry: change this to just use distance between center points.
899 int cur_dist = DistanceSquaredFromCenterLineToPoint(touch_center,
900 cur_rect);
901 if (!rect_view || cur_dist < rect_view_distance) {
902 rect_view = cur_view;
903 rect_view_distance = cur_dist;
904 }
905 } else if (!rect_view && !point_view) {
906 // Rect-based targeting has not yielded any candidates so far. Check
907 // if point-based targeting would have selected |cur_view|.
908 gfx::Point point_in_child_coords(rect.CenterPoint());
909 ConvertPointToTarget(this, child, &point_in_child_coords);
910 if (child->HitTestPoint(point_in_child_coords))
sky 2013/09/06 19:56:47 HitTestPoint isn't enough, you really need to be i
tdanderson 2013/09/09 22:15:39 Done.
911 point_view = cur_view;
912 }
840 } 913 }
841 return this; 914
915 if (UsePointBasedTargeting(rect) || (!rect_view && !point_view))
916 return this;
917
918 return rect_view ? rect_view : point_view;
842 } 919 }
843 920
844 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) { 921 View* View::GetTooltipHandlerForPoint(const gfx::Point& point) {
845 if (!HitTestPoint(point)) 922 if (!HitTestPoint(point))
846 return NULL; 923 return NULL;
847 924
848 // Walk the child Views recursively looking for the View that most 925 // Walk the child Views recursively looking for the View that most
849 // tightly encloses the specified point. 926 // tightly encloses the specified point.
850 for (int i = child_count() - 1; i >= 0; --i) { 927 for (int i = child_count() - 1; i >= 0; --i) {
851 View* child = child_at(i); 928 View* child = child_at(i);
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after
1262 int View::GetPageScrollIncrement(ScrollView* scroll_view, 1339 int View::GetPageScrollIncrement(ScrollView* scroll_view,
1263 bool is_horizontal, bool is_positive) { 1340 bool is_horizontal, bool is_positive) {
1264 return 0; 1341 return 0;
1265 } 1342 }
1266 1343
1267 int View::GetLineScrollIncrement(ScrollView* scroll_view, 1344 int View::GetLineScrollIncrement(ScrollView* scroll_view,
1268 bool is_horizontal, bool is_positive) { 1345 bool is_horizontal, bool is_positive) {
1269 return 0; 1346 return 0;
1270 } 1347 }
1271 1348
1349 // Views fuzzing ---------------------------------------------------------------
1350
1351 // static
1352 bool View::UsePointBasedTargeting(const gfx::Rect& rect) {
1353 return rect.width() == 1 && rect.height() == 1;
1354 }
1355
1356 // static
1357 float View::PercentCoveredBy(const gfx::Rect& rect_1, const gfx::Rect& rect_2) {
1358 gfx::Rect intersection(rect_1);
1359 intersection.Intersect(rect_2);
1360 float intersection_area = intersection.size().GetArea();
1361 float rect_1_area = rect_1.size().GetArea();
1362 return rect_1_area ? intersection_area / rect_1_area : 0;
1363 }
1364
1365 // The positive distance from |pos| to the nearest endpoint of the interval
1366 // [start, end] is returned if |pos| lies within the interval, otherwise
1367 // 0 is returned.
1368 int DistanceToInterval(int pos, int start, int end) {
1369 if (pos < start)
1370 return start - pos;
1371 if (pos > end)
1372 return pos - end;
1373 return 0;
1374 }
1375
1376 // static
1377 int View::DistanceSquaredFromCenterLineToPoint(const gfx::Point& point,
1378 const gfx::Rect& target_rect) {
1379 gfx::Point center_point = target_rect.CenterPoint();
1380 int dx = center_point.x() - point.x();
1381 int dy = center_point.y() - point.y();
1382
1383 if (target_rect.width() > target_rect.height()) {
1384 dx = DistanceToInterval(point.x(),
1385 target_rect.x() + (target_rect.height() / 2),
1386 target_rect.right() - (target_rect.height() / 2));
1387 } else {
1388 dy = DistanceToInterval(point.y(),
1389 target_rect.y() + (target_rect.width() / 2),
1390 target_rect.bottom() - (target_rect.width() / 2));
1391 }
1392 return (dx * dx) + (dy * dy);
1393 }
1394
1272 //////////////////////////////////////////////////////////////////////////////// 1395 ////////////////////////////////////////////////////////////////////////////////
1273 // View, protected: 1396 // View, protected:
1274 1397
1275 // Size and disposition -------------------------------------------------------- 1398 // Size and disposition --------------------------------------------------------
1276 1399
1277 void View::OnBoundsChanged(const gfx::Rect& previous_bounds) { 1400 void View::OnBoundsChanged(const gfx::Rect& previous_bounds) {
1278 } 1401 }
1279 1402
1280 void View::PreferredSizeChanged() { 1403 void View::PreferredSizeChanged() {
1281 InvalidateLayout(); 1404 InvalidateLayout();
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after
2007 bool View::ConvertPointFromAncestor(const View* ancestor, 2130 bool View::ConvertPointFromAncestor(const View* ancestor,
2008 gfx::Point* point) const { 2131 gfx::Point* point) const {
2009 gfx::Transform trans; 2132 gfx::Transform trans;
2010 bool result = GetTransformRelativeTo(ancestor, &trans); 2133 bool result = GetTransformRelativeTo(ancestor, &trans);
2011 gfx::Point3F p(*point); 2134 gfx::Point3F p(*point);
2012 trans.TransformPointReverse(p); 2135 trans.TransformPointReverse(p);
2013 *point = gfx::ToFlooredPoint(p.AsPointF()); 2136 *point = gfx::ToFlooredPoint(p.AsPointF());
2014 return result; 2137 return result;
2015 } 2138 }
2016 2139
2140 bool View::ConvertRectForAncestor(const View* ancestor,
2141 gfx::Rect* rect) const {
2142 gfx::Transform trans;
2143 // TODO(sad): Have some way of caching the transformation results.
2144 bool result = GetTransformRelativeTo(ancestor, &trans);
2145 gfx::RectF r(*rect);
2146 trans.TransformRect(&r);
2147 *rect = gfx::ToFlooredRect(r);
2148 return result;
2149 }
2150
2151 bool View::ConvertRectFromAncestor(const View* ancestor,
2152 gfx::Rect* rect) const {
2153 gfx::Transform trans;
2154 bool result = GetTransformRelativeTo(ancestor, &trans);
2155 gfx::RectF r(*rect);
2156 trans.TransformRectReverse(&r);
2157 *rect = gfx::ToFlooredRect(r);
2158 return result;
2159 }
2160
2017 // Accelerated painting -------------------------------------------------------- 2161 // Accelerated painting --------------------------------------------------------
2018 2162
2019 void View::CreateLayer() { 2163 void View::CreateLayer() {
2020 // A new layer is being created for the view. So all the layers of the 2164 // A new layer is being created for the view. So all the layers of the
2021 // sub-tree can inherit the visibility of the corresponding view. 2165 // sub-tree can inherit the visibility of the corresponding view.
2022 for (int i = 0, count = child_count(); i < count; ++i) 2166 for (int i = 0, count = child_count(); i < count; ++i)
2023 child_at(i)->UpdateChildLayerVisibility(true); 2167 child_at(i)->UpdateChildLayerVisibility(true);
2024 2168
2025 layer_ = new ui::Layer(); 2169 layer_ = new ui::Layer();
2026 layer_owner_.reset(layer_); 2170 layer_owner_.reset(layer_);
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
2320 ConvertPointToWidget(this, &widget_location); 2464 ConvertPointToWidget(this, &widget_location);
2321 widget->RunShellDrag(this, data, widget_location, drag_operations, source); 2465 widget->RunShellDrag(this, data, widget_location, drag_operations, source);
2322 // WARNING: we may have been deleted. 2466 // WARNING: we may have been deleted.
2323 return true; 2467 return true;
2324 #else 2468 #else
2325 return false; 2469 return false;
2326 #endif // !defined(OS_MACOSX) 2470 #endif // !defined(OS_MACOSX)
2327 } 2471 }
2328 2472
2329 } // namespace views 2473 } // namespace views
OLDNEW
« ui/gfx/point_conversions.h ('K') | « ui/views/view.h ('k') | ui/views/widget/root_view.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698