| 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 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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) { |
| 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) { |
| 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) { |
| 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()); |
| 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)) |
| 911 point_view = child->GetEventHandlerForPoint(point_in_child_coords); |
| 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::ToEnclosingRect(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::ToEnclosingRect(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 |