1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/view_targeter_delegate.h"
7 #include "ui/gfx/geometry/rect_conversions.h"
8 #include "ui/views/rect_based_targeting_utils.h"
9 #include "ui/views/view.h"
13 // The minimum percentage of a view's area that needs to be covered by a rect
14 // representing a touch region in order for that view to be considered by the
15 // rect-based targeting algorithm.
16 static const float kRectTargetOverlap
= 0.6f
;
22 // TODO(tdanderson): Move the contents of rect_based_targeting_utils.(h|cc)
25 bool ViewTargeterDelegate::DoesIntersectRect(const View
* target
,
26 const gfx::Rect
& rect
) const {
27 return target
->GetLocalBounds().Intersects(rect
);
30 View
* ViewTargeterDelegate::TargetForRect(View
* root
, const gfx::Rect
& rect
) {
31 // |rect_view| represents the current best candidate to return
32 // if rect-based targeting (i.e., fuzzing) is used.
33 // |rect_view_distance| is used to keep track of the distance
34 // between the center point of |rect_view| and the center
36 View
* rect_view
= NULL
;
37 int rect_view_distance
= INT_MAX
;
39 // |point_view| represents the view that would have been returned
40 // from this function call if point-based targeting were used.
41 View
* point_view
= NULL
;
43 for (int i
= root
->child_count() - 1; i
>= 0; --i
) {
44 View
* child
= root
->child_at(i
);
46 if (!child
->CanProcessEventsWithinSubtree())
49 // Ignore any children which are invisible or do not intersect |rect|.
50 if (!child
->visible())
52 gfx::RectF
rect_in_child_coords_f(rect
);
53 View::ConvertRectToTarget(root
, child
, &rect_in_child_coords_f
);
54 gfx::Rect rect_in_child_coords
= gfx::ToEnclosingRect(
55 rect_in_child_coords_f
);
56 if (!child
->HitTestRect(rect_in_child_coords
))
59 View
* cur_view
= child
->GetEventHandlerForRect(rect_in_child_coords
);
61 if (views::UsePointBasedTargeting(rect
))
64 gfx::RectF
cur_view_bounds_f(cur_view
->GetLocalBounds());
65 View::ConvertRectToTarget(cur_view
, root
, &cur_view_bounds_f
);
66 gfx::Rect cur_view_bounds
= gfx::ToEnclosingRect(
68 if (views::PercentCoveredBy(cur_view_bounds
, rect
) >= kRectTargetOverlap
) {
69 // |cur_view| is a suitable candidate for rect-based targeting.
70 // Check to see if it is the closest suitable candidate so far.
71 gfx::Point
touch_center(rect
.CenterPoint());
72 int cur_dist
= views::DistanceSquaredFromCenterToPoint(touch_center
,
74 if (!rect_view
|| cur_dist
< rect_view_distance
) {
76 rect_view_distance
= cur_dist
;
78 } else if (!rect_view
&& !point_view
) {
79 // Rect-based targeting has not yielded any candidates so far. Check
80 // if point-based targeting would have selected |cur_view|.
81 gfx::Point
point_in_child_coords(rect_in_child_coords
.CenterPoint());
82 if (child
->HitTestPoint(point_in_child_coords
))
83 point_view
= child
->GetEventHandlerForPoint(point_in_child_coords
);
87 if (views::UsePointBasedTargeting(rect
) || (!rect_view
&& !point_view
))
90 // If |root| is a suitable candidate for rect-based targeting, check to
91 // see if it is closer than the current best suitable candidate so far.
92 gfx::Rect
local_bounds(root
->GetLocalBounds());
93 if (views::PercentCoveredBy(local_bounds
, rect
) >= kRectTargetOverlap
) {
94 gfx::Point
touch_center(rect
.CenterPoint());
95 int cur_dist
= views::DistanceSquaredFromCenterToPoint(touch_center
,
97 if (!rect_view
|| cur_dist
< rect_view_distance
)
101 return rect_view
? rect_view
: point_view
;