diff options
author | tdanderson@chromium.org <tdanderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-19 20:03:45 +0000 |
---|---|---|
committer | tdanderson@chromium.org <tdanderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-19 20:03:45 +0000 |
commit | 4107371c15f222de836fc4f2122af8a2a79402f0 (patch) | |
tree | d7bc3cd7d2d916b98498ae2fe3205eec13a5137b /ui/views/view_targeter_delegate.cc | |
parent | 4eef7525849fb56a7720b1c42e0c44fc2f11b36d (diff) | |
download | chromium_src-4107371c15f222de836fc4f2122af8a2a79402f0.zip chromium_src-4107371c15f222de836fc4f2122af8a2a79402f0.tar.gz chromium_src-4107371c15f222de836fc4f2122af8a2a79402f0.tar.bz2 |
Move views event targeting into ViewTargeterDelegate::TargetForRect()
Move the default event-targeting implementation for views from
View::GetEventHandlerForRect() into the new method
ViewTargeterDelegate::TargetForRect() and make the method
View::GetEventHandlerForRect() call into its effective ViewTargeter
instead. The "effective" targeter for a View is the
ViewTargeter installed on that View if one exists, otherwise
it is the ViewTargeter installed on its root view.
Once this change has landed, the overrides of
View::GetEventHandlerForRect() can be removed and their
implementations moved into overrides of
ViewTargeterDelegate::TargetForRect().
View::GetEventHandlerForRect() can then be made
non-virtual.
BUG=391845
TEST=existing coverage in ViewTest.GetEventHandlerForRect
Review URL: https://codereview.chromium.org/401933002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284342 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/views/view_targeter_delegate.cc')
-rw-r--r-- | ui/views/view_targeter_delegate.cc | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/ui/views/view_targeter_delegate.cc b/ui/views/view_targeter_delegate.cc index 5527742..7d4556a 100644 --- a/ui/views/view_targeter_delegate.cc +++ b/ui/views/view_targeter_delegate.cc @@ -2,14 +2,103 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/views/view.h" #include "ui/views/view_targeter_delegate.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/views/rect_based_targeting_utils.h" +#include "ui/views/view.h" + +namespace { + +// The minimum percentage of a view's area that needs to be covered by a rect +// representing a touch region in order for that view to be considered by the +// rect-based targeting algorithm. +static const float kRectTargetOverlap = 0.6f; + +} // namespace + namespace views { +// TODO(tdanderson): Move the contents of rect_based_targeting_utils.(h|cc) +// into here. + bool ViewTargeterDelegate::DoesIntersectRect(const View* target, const gfx::Rect& rect) const { return target->GetLocalBounds().Intersects(rect); } +View* ViewTargeterDelegate::TargetForRect(View* root, const gfx::Rect& rect) { + // |rect_view| represents the current best candidate to return + // if rect-based targeting (i.e., fuzzing) is used. + // |rect_view_distance| is used to keep track of the distance + // between the center point of |rect_view| and the center + // point of |rect|. + View* rect_view = NULL; + int rect_view_distance = INT_MAX; + + // |point_view| represents the view that would have been returned + // from this function call if point-based targeting were used. + View* point_view = NULL; + + for (int i = root->child_count() - 1; i >= 0; --i) { + View* child = root->child_at(i); + + if (!child->CanProcessEventsWithinSubtree()) + continue; + + // Ignore any children which are invisible or do not intersect |rect|. + if (!child->visible()) + continue; + gfx::RectF rect_in_child_coords_f(rect); + View::ConvertRectToTarget(root, child, &rect_in_child_coords_f); + gfx::Rect rect_in_child_coords = gfx::ToEnclosingRect( + rect_in_child_coords_f); + if (!child->HitTestRect(rect_in_child_coords)) + continue; + + View* cur_view = child->GetEventHandlerForRect(rect_in_child_coords); + + if (views::UsePointBasedTargeting(rect)) + return cur_view; + + gfx::RectF cur_view_bounds_f(cur_view->GetLocalBounds()); + View::ConvertRectToTarget(cur_view, root, &cur_view_bounds_f); + gfx::Rect cur_view_bounds = gfx::ToEnclosingRect( + cur_view_bounds_f); + if (views::PercentCoveredBy(cur_view_bounds, rect) >= kRectTargetOverlap) { + // |cur_view| is a suitable candidate for rect-based targeting. + // Check to see if it is the closest suitable candidate so far. + gfx::Point touch_center(rect.CenterPoint()); + int cur_dist = views::DistanceSquaredFromCenterToPoint(touch_center, + cur_view_bounds); + if (!rect_view || cur_dist < rect_view_distance) { + rect_view = cur_view; + rect_view_distance = cur_dist; + } + } else if (!rect_view && !point_view) { + // Rect-based targeting has not yielded any candidates so far. Check + // if point-based targeting would have selected |cur_view|. + gfx::Point point_in_child_coords(rect_in_child_coords.CenterPoint()); + if (child->HitTestPoint(point_in_child_coords)) + point_view = child->GetEventHandlerForPoint(point_in_child_coords); + } + } + + if (views::UsePointBasedTargeting(rect) || (!rect_view && !point_view)) + return root; + + // If |root| is a suitable candidate for rect-based targeting, check to + // see if it is closer than the current best suitable candidate so far. + gfx::Rect local_bounds(root->GetLocalBounds()); + if (views::PercentCoveredBy(local_bounds, rect) >= kRectTargetOverlap) { + gfx::Point touch_center(rect.CenterPoint()); + int cur_dist = views::DistanceSquaredFromCenterToPoint(touch_center, + local_bounds); + if (!rect_view || cur_dist < rect_view_distance) + rect_view = root; + } + + return rect_view ? rect_view : point_view; +} + } // namespace views |