OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |