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

Side by Side Diff: cc/trees/layer_tree_impl.cc

Issue 266913021: Hit test on the layer tree rather than the RSLL (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Minor cleanups. Created 6 years, 7 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 2011 The Chromium Authors. All rights reserved. 1 // Copyright 2011 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 #include "cc/trees/layer_tree_impl.h" 5 #include "cc/trees/layer_tree_impl.h"
6 6
7 #include "base/debug/trace_event.h" 7 #include "base/debug/trace_event.h"
8 #include "cc/animation/keyframed_animation_curve.h" 8 #include "cc/animation/keyframed_animation_curve.h"
9 #include "cc/animation/scrollbar_animation_controller.h" 9 #include "cc/animation/scrollbar_animation_controller.h"
10 #include "cc/animation/scrollbar_animation_controller_linear_fade.h" 10 #include "cc/animation/scrollbar_animation_controller_linear_fade.h"
11 #include "cc/animation/scrollbar_animation_controller_thinning.h" 11 #include "cc/animation/scrollbar_animation_controller_thinning.h"
12 #include "cc/base/math_util.h" 12 #include "cc/base/math_util.h"
13 #include "cc/base/util.h" 13 #include "cc/base/util.h"
14 #include "cc/debug/traced_value.h" 14 #include "cc/debug/traced_value.h"
15 #include "cc/layers/heads_up_display_layer_impl.h" 15 #include "cc/layers/heads_up_display_layer_impl.h"
16 #include "cc/layers/layer.h" 16 #include "cc/layers/layer.h"
17 #include "cc/layers/layer_iterator.h" 17 #include "cc/layers/layer_iterator.h"
18 #include "cc/layers/render_surface_impl.h" 18 #include "cc/layers/render_surface_impl.h"
19 #include "cc/layers/scrollbar_layer_impl_base.h" 19 #include "cc/layers/scrollbar_layer_impl_base.h"
20 #include "cc/resources/ui_resource_request.h" 20 #include "cc/resources/ui_resource_request.h"
21 #include "cc/trees/layer_tree_host_common.h" 21 #include "cc/trees/layer_tree_host_common.h"
22 #include "cc/trees/layer_tree_host_impl.h" 22 #include "cc/trees/layer_tree_host_impl.h"
23 #include "ui/gfx/point_conversions.h"
23 #include "ui/gfx/size_conversions.h" 24 #include "ui/gfx/size_conversions.h"
24 #include "ui/gfx/vector2d_conversions.h" 25 #include "ui/gfx/vector2d_conversions.h"
25 26
26 namespace cc { 27 namespace cc {
27 28
28 // This class exists to split the LayerScrollOffsetDelegate between the 29 // This class exists to split the LayerScrollOffsetDelegate between the
29 // InnerViewportScrollLayer and the OuterViewportScrollLayer in a manner 30 // InnerViewportScrollLayer and the OuterViewportScrollLayer in a manner
30 // that never requires the embedder or LayerImpl to know about. 31 // that never requires the embedder or LayerImpl to know about.
31 class LayerScrollOffsetDelegateProxy : public LayerScrollOffsetDelegate { 32 class LayerScrollOffsetDelegateProxy : public LayerScrollOffsetDelegate {
32 public: 33 public:
(...skipping 955 matching lines...) Expand 10 before | Expand all | Expand 10 after
988 989
989 const std::vector<LayerImpl*>& LayerTreeImpl::LayersWithCopyOutputRequest() 990 const std::vector<LayerImpl*>& LayerTreeImpl::LayersWithCopyOutputRequest()
990 const { 991 const {
991 // Only the active tree needs to know about layers with copy requests, as 992 // Only the active tree needs to know about layers with copy requests, as
992 // they are aborted if not serviced during draw. 993 // they are aborted if not serviced during draw.
993 DCHECK(IsActiveTree()); 994 DCHECK(IsActiveTree());
994 995
995 return layers_with_copy_output_request_; 996 return layers_with_copy_output_request_;
996 } 997 }
997 998
999 template <typename LayerType>
1000 static inline bool LayerClipsSubtree(LayerType* layer) {
1001 return layer->masks_to_bounds() || layer->mask_layer();
1002 }
1003
1004 static bool PointHitsRect(
1005 const gfx::PointF& screen_space_point,
1006 const gfx::Transform& local_space_to_screen_space_transform,
1007 const gfx::RectF& local_space_rect,
1008 float* distance_to_camera) {
1009 // If the transform is not invertible, then assume that this point doesn't hit
1010 // this rect.
1011 gfx::Transform inverse_local_space_to_screen_space(
1012 gfx::Transform::kSkipInitialization);
1013 if (!local_space_to_screen_space_transform.GetInverse(
1014 &inverse_local_space_to_screen_space))
1015 return false;
1016
1017 // Transform the hit test point from screen space to the local space of the
1018 // given rect.
1019 bool clipped = false;
1020 gfx::Point3F planar_point = MathUtil::ProjectPoint3D(
1021 inverse_local_space_to_screen_space, screen_space_point, &clipped);
1022 gfx::PointF hit_test_point_in_local_space =
1023 gfx::PointF(planar_point.x(), planar_point.y());
1024
1025 // If ProjectPoint could not project to a valid value, then we assume that
1026 // this point doesn't hit this rect.
1027 if (clipped)
1028 return false;
1029
1030 if (!local_space_rect.Contains(hit_test_point_in_local_space))
1031 return false;
1032
1033 if (distance_to_camera) {
1034 // To compute the distance to the camera, we have to take the planar point
1035 // and pull it back to world space and compute the displacement along the
1036 // z-axis.
1037 gfx::Point3F planar_point_in_screen_space(planar_point);
1038 local_space_to_screen_space_transform.TransformPoint(
1039 &planar_point_in_screen_space);
1040 *distance_to_camera = planar_point_in_screen_space.z();
1041 }
1042
1043 return true;
1044 }
1045
1046 static bool PointHitsRegion(const gfx::PointF& screen_space_point,
1047 const gfx::Transform& screen_space_transform,
1048 const Region& layer_space_region,
1049 float layer_content_scale_x,
1050 float layer_content_scale_y) {
1051 // If the transform is not invertible, then assume that this point doesn't hit
1052 // this region.
1053 gfx::Transform inverse_screen_space_transform(
1054 gfx::Transform::kSkipInitialization);
1055 if (!screen_space_transform.GetInverse(&inverse_screen_space_transform))
1056 return false;
1057
1058 // Transform the hit test point from screen space to the local space of the
1059 // given region.
1060 bool clipped = false;
1061 gfx::PointF hit_test_point_in_content_space = MathUtil::ProjectPoint(
1062 inverse_screen_space_transform, screen_space_point, &clipped);
1063 gfx::PointF hit_test_point_in_layer_space =
1064 gfx::ScalePoint(hit_test_point_in_content_space,
1065 1.f / layer_content_scale_x,
1066 1.f / layer_content_scale_y);
1067
1068 // If ProjectPoint could not project to a valid value, then we assume that
1069 // this point doesn't hit this region.
1070 if (clipped)
1071 return false;
1072
1073 return layer_space_region.Contains(
1074 gfx::ToRoundedPoint(hit_test_point_in_layer_space));
1075 }
1076
1077 static bool PointIsClippedBySurfaceOrClipRect(
1078 const gfx::PointF& screen_space_point,
1079 LayerImpl* layer) {
1080 LayerImpl* current_layer = layer;
1081
1082 // Walk up the layer tree and hit-test any render_surfaces and any layer
1083 // clip rects that are active.
1084 while (current_layer) {
1085 if (current_layer->render_surface() &&
1086 !PointHitsRect(
1087 screen_space_point,
1088 current_layer->render_surface()->screen_space_transform(),
1089 current_layer->render_surface()->content_rect(),
1090 NULL))
1091 return true;
1092
1093 // Note that drawable content rects are actually in target surface space, so
1094 // the transform we have to provide is the target surface's
1095 // screen_space_transform.
1096 LayerImpl* render_target = current_layer->render_target();
1097 if (LayerClipsSubtree(current_layer) &&
1098 !PointHitsRect(
1099 screen_space_point,
1100 render_target->render_surface()->screen_space_transform(),
1101 current_layer->drawable_content_rect(),
1102 NULL))
1103 return true;
1104
1105 current_layer = current_layer->parent();
1106 }
1107
1108 // If we have finished walking all ancestors without having already exited,
1109 // then the point is not clipped by any ancestors.
1110 return false;
1111 }
1112
1113 static bool PointHitsLayer(LayerImpl* layer,
1114 const gfx::PointF& screen_space_point,
1115 float* distance_to_intersection) {
1116 gfx::RectF content_rect(layer->content_bounds());
1117 if (!PointHitsRect(screen_space_point,
1118 layer->screen_space_transform(),
1119 content_rect,
1120 distance_to_intersection))
1121 return false;
1122
1123 // At this point, we think the point does hit the layer, but we need to walk
1124 // up the parents to ensure that the layer was not clipped in such a way
1125 // that the hit point actually should not hit the layer.
1126 if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer))
1127 return false;
1128
1129 // Skip the HUD layer.
1130 if (layer == layer->layer_tree_impl()->hud_layer())
1131 return false;
1132
1133 return true;
1134 }
1135
1136 struct FindClosestMatchingLayerDataForRecursion {
1137 FindClosestMatchingLayerDataForRecursion()
1138 : closest_match(NULL), closest_distance(0.f), found_match(false) {}
1139 LayerImpl* closest_match;
1140 // Note that the positive z-axis points towards the camera, so bigger means
1141 // closer in this case, counterintuitively.
1142 float closest_distance;
1143 bool found_match;
1144 };
1145
1146 template <typename Functor>
1147 static void FindClosestMatchingLayer(
1148 const gfx::PointF& screen_space_point,
1149 LayerImpl* layer,
1150 const Functor& func,
1151 FindClosestMatchingLayerDataForRecursion* data_for_recursion) {
1152 for (int i = layer->children().size() - 1; i >= 0; --i) {
1153 FindClosestMatchingLayer(
1154 screen_space_point, layer->children()[i], func, data_for_recursion);
1155 }
1156
1157 float distance_to_intersection = 0.f;
1158 if (func(layer) &&
1159 PointHitsLayer(layer, screen_space_point, &distance_to_intersection) &&
1160 ((!data_for_recursion->found_match ||
1161 distance_to_intersection > data_for_recursion->closest_distance))) {
1162 data_for_recursion->found_match = true;
1163 data_for_recursion->closest_distance = distance_to_intersection;
1164 data_for_recursion->closest_match = layer;
1165 }
1166 }
1167
1168 struct FindScrollingLayerFunctor {
1169 bool operator()(LayerImpl* layer) const { return layer->scrollable(); }
1170 };
1171
1172 LayerImpl* LayerTreeImpl::FindFirstScrollingLayerThatIsHitByPoint(
1173 const gfx::PointF& screen_space_point) {
1174 FindClosestMatchingLayerDataForRecursion data_for_recursion;
1175 FindClosestMatchingLayer(screen_space_point,
1176 root_layer(),
1177 FindScrollingLayerFunctor(),
1178 &data_for_recursion);
1179 return data_for_recursion.closest_match;
1180 }
1181
1182 struct HitTestVisibleFunctor {
1183 bool operator()(LayerImpl* layer) const {
1184 return layer->IsDrawnRenderSurfaceLayerListMember() ||
1185 !layer->touch_event_handler_region().IsEmpty() ||
1186 layer->have_wheel_event_handlers();
1187 }
1188 };
1189
1190 LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPoint(
1191 const gfx::PointF& screen_space_point) {
1192 FindClosestMatchingLayerDataForRecursion data_for_recursion;
1193 FindClosestMatchingLayer(screen_space_point,
1194 root_layer(),
1195 HitTestVisibleFunctor(),
1196 &data_for_recursion);
1197 return data_for_recursion.closest_match;
1198 }
1199
1200 static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point,
1201 LayerImpl* layer_impl) {
1202 if (layer_impl->touch_event_handler_region().IsEmpty())
1203 return false;
1204
1205 if (!PointHitsRegion(screen_space_point,
1206 layer_impl->screen_space_transform(),
1207 layer_impl->touch_event_handler_region(),
1208 layer_impl->contents_scale_x(),
1209 layer_impl->contents_scale_y()))
1210 return false;
1211
1212 // At this point, we think the point does hit the touch event handler region
1213 // on the layer, but we need to walk up the parents to ensure that the layer
1214 // was not clipped in such a way that the hit point actually should not hit
1215 // the layer.
1216 if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl))
1217 return false;
1218
1219 return true;
1220 }
1221
1222 struct FindTouchEventLayerFunctor {
1223 bool operator()(LayerImpl* layer) const {
1224 return LayerHasTouchEventHandlersAt(screen_space_point, layer);
1225 }
1226 const gfx::PointF screen_space_point;
1227 };
1228
1229 LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
1230 const gfx::PointF& screen_space_point) {
1231 FindTouchEventLayerFunctor func = {screen_space_point};
1232 FindClosestMatchingLayerDataForRecursion data_for_recursion;
1233 FindClosestMatchingLayer(
1234 screen_space_point, root_layer(), func, &data_for_recursion);
1235 return data_for_recursion.closest_match;
1236 }
1237
998 } // namespace cc 1238 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698