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

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: Helps if you upload all your files. 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
« no previous file with comments | « cc/trees/layer_tree_impl.h ('k') | cc/trees/layer_tree_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <limits>
8 #include <set>
9
7 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
8 #include "cc/animation/keyframed_animation_curve.h" 11 #include "cc/animation/keyframed_animation_curve.h"
9 #include "cc/animation/scrollbar_animation_controller.h" 12 #include "cc/animation/scrollbar_animation_controller.h"
10 #include "cc/animation/scrollbar_animation_controller_linear_fade.h" 13 #include "cc/animation/scrollbar_animation_controller_linear_fade.h"
11 #include "cc/animation/scrollbar_animation_controller_thinning.h" 14 #include "cc/animation/scrollbar_animation_controller_thinning.h"
12 #include "cc/base/math_util.h" 15 #include "cc/base/math_util.h"
13 #include "cc/base/util.h" 16 #include "cc/base/util.h"
14 #include "cc/debug/traced_value.h" 17 #include "cc/debug/traced_value.h"
15 #include "cc/layers/heads_up_display_layer_impl.h" 18 #include "cc/layers/heads_up_display_layer_impl.h"
16 #include "cc/layers/layer.h" 19 #include "cc/layers/layer.h"
17 #include "cc/layers/layer_iterator.h" 20 #include "cc/layers/layer_iterator.h"
18 #include "cc/layers/render_surface_impl.h" 21 #include "cc/layers/render_surface_impl.h"
19 #include "cc/layers/scrollbar_layer_impl_base.h" 22 #include "cc/layers/scrollbar_layer_impl_base.h"
20 #include "cc/resources/ui_resource_request.h" 23 #include "cc/resources/ui_resource_request.h"
21 #include "cc/trees/layer_tree_host_common.h" 24 #include "cc/trees/layer_tree_host_common.h"
22 #include "cc/trees/layer_tree_host_impl.h" 25 #include "cc/trees/layer_tree_host_impl.h"
26 #include "ui/gfx/point_conversions.h"
23 #include "ui/gfx/size_conversions.h" 27 #include "ui/gfx/size_conversions.h"
24 #include "ui/gfx/vector2d_conversions.h" 28 #include "ui/gfx/vector2d_conversions.h"
25 29
26 namespace cc { 30 namespace cc {
27 31
28 // This class exists to split the LayerScrollOffsetDelegate between the 32 // This class exists to split the LayerScrollOffsetDelegate between the
29 // InnerViewportScrollLayer and the OuterViewportScrollLayer in a manner 33 // InnerViewportScrollLayer and the OuterViewportScrollLayer in a manner
30 // that never requires the embedder or LayerImpl to know about. 34 // that never requires the embedder or LayerImpl to know about.
31 class LayerScrollOffsetDelegateProxy : public LayerScrollOffsetDelegate { 35 class LayerScrollOffsetDelegateProxy : public LayerScrollOffsetDelegate {
32 public: 36 public:
(...skipping 982 matching lines...) Expand 10 before | Expand all | Expand 10 after
1015 DCHECK(current); 1019 DCHECK(current);
1016 current->ReleaseResources(); 1020 current->ReleaseResources();
1017 if (current->mask_layer()) 1021 if (current->mask_layer())
1018 ReleaseResourcesRecursive(current->mask_layer()); 1022 ReleaseResourcesRecursive(current->mask_layer());
1019 if (current->replica_layer()) 1023 if (current->replica_layer())
1020 ReleaseResourcesRecursive(current->replica_layer()); 1024 ReleaseResourcesRecursive(current->replica_layer());
1021 for (size_t i = 0; i < current->children().size(); ++i) 1025 for (size_t i = 0; i < current->children().size(); ++i)
1022 ReleaseResourcesRecursive(current->children()[i]); 1026 ReleaseResourcesRecursive(current->children()[i]);
1023 } 1027 }
1024 1028
1029 template <typename LayerType>
1030 static inline bool LayerClipsSubtree(LayerType* layer) {
1031 return layer->masks_to_bounds() || layer->mask_layer();
1032 }
1033
1034 static bool PointHitsRect(
1035 const gfx::PointF& screen_space_point,
1036 const gfx::Transform& local_space_to_screen_space_transform,
1037 const gfx::RectF& local_space_rect,
1038 float* distance_to_camera) {
1039 // If the transform is not invertible, then assume that this point doesn't hit
1040 // this rect.
1041 gfx::Transform inverse_local_space_to_screen_space(
1042 gfx::Transform::kSkipInitialization);
1043 if (!local_space_to_screen_space_transform.GetInverse(
1044 &inverse_local_space_to_screen_space))
1045 return false;
1046
1047 // Transform the hit test point from screen space to the local space of the
1048 // given rect.
1049 bool clipped = false;
1050 gfx::Point3F planar_point = MathUtil::ProjectPoint3D(
1051 inverse_local_space_to_screen_space, screen_space_point, &clipped);
1052 gfx::PointF hit_test_point_in_local_space =
1053 gfx::PointF(planar_point.x(), planar_point.y());
1054
1055 // If ProjectPoint could not project to a valid value, then we assume that
1056 // this point doesn't hit this rect.
1057 if (clipped)
1058 return false;
1059
1060 if (!local_space_rect.Contains(hit_test_point_in_local_space))
1061 return false;
1062
1063 if (distance_to_camera) {
1064 // To compute the distance to the camera, we have to take the planar point
1065 // and pull it back to world space and compute the displacement along the
1066 // z-axis.
1067 gfx::Point3F planar_point_in_screen_space(planar_point);
1068 local_space_to_screen_space_transform.TransformPoint(
1069 &planar_point_in_screen_space);
1070 *distance_to_camera = planar_point_in_screen_space.z();
1071 }
1072
1073 return true;
1074 }
1075
1076 static bool PointHitsRegion(const gfx::PointF& screen_space_point,
1077 const gfx::Transform& screen_space_transform,
1078 const Region& layer_space_region,
1079 float layer_content_scale_x,
1080 float layer_content_scale_y) {
1081 // If the transform is not invertible, then assume that this point doesn't hit
1082 // this region.
1083 gfx::Transform inverse_screen_space_transform(
1084 gfx::Transform::kSkipInitialization);
1085 if (!screen_space_transform.GetInverse(&inverse_screen_space_transform))
1086 return false;
1087
1088 // Transform the hit test point from screen space to the local space of the
1089 // given region.
1090 bool clipped = false;
1091 gfx::PointF hit_test_point_in_content_space = MathUtil::ProjectPoint(
1092 inverse_screen_space_transform, screen_space_point, &clipped);
1093 gfx::PointF hit_test_point_in_layer_space =
1094 gfx::ScalePoint(hit_test_point_in_content_space,
1095 1.f / layer_content_scale_x,
1096 1.f / layer_content_scale_y);
1097
1098 // If ProjectPoint could not project to a valid value, then we assume that
1099 // this point doesn't hit this region.
1100 if (clipped)
1101 return false;
1102
1103 return layer_space_region.Contains(
1104 gfx::ToRoundedPoint(hit_test_point_in_layer_space));
1105 }
1106
1107 static bool PointIsClippedBySurfaceOrClipRect(
1108 const gfx::PointF& screen_space_point,
1109 LayerImpl* layer) {
1110 LayerImpl* current_layer = layer;
1111
1112 // Walk up the layer tree and hit-test any render_surfaces and any layer
1113 // clip rects that are active.
1114 while (current_layer) {
1115 if (current_layer->render_surface() &&
1116 !PointHitsRect(
1117 screen_space_point,
1118 current_layer->render_surface()->screen_space_transform(),
1119 current_layer->render_surface()->content_rect(),
1120 NULL))
1121 return true;
1122
1123 // Note that drawable content rects are actually in target surface space, so
1124 // the transform we have to provide is the target surface's
1125 // screen_space_transform.
1126 LayerImpl* render_target = current_layer->render_target();
1127 if (LayerClipsSubtree(current_layer) &&
1128 !PointHitsRect(
1129 screen_space_point,
1130 render_target->render_surface()->screen_space_transform(),
1131 current_layer->drawable_content_rect(),
1132 NULL))
1133 return true;
1134
1135 current_layer = current_layer->parent();
1136 }
1137
1138 // If we have finished walking all ancestors without having already exited,
1139 // then the point is not clipped by any ancestors.
1140 return false;
1141 }
1142
1143 static bool PointHitsLayer(LayerImpl* layer,
1144 const gfx::PointF& screen_space_point,
1145 float* distance_to_intersection) {
1146 gfx::RectF content_rect(layer->content_bounds());
1147 if (!PointHitsRect(screen_space_point,
1148 layer->screen_space_transform(),
1149 content_rect,
1150 distance_to_intersection))
1151 return false;
1152
1153 // At this point, we think the point does hit the layer, but we need to walk
1154 // up the parents to ensure that the layer was not clipped in such a way
1155 // that the hit point actually should not hit the layer.
1156 if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer))
1157 return false;
1158
1159 // Skip the HUD layer.
1160 if (layer == layer->layer_tree_impl()->hud_layer())
1161 return false;
1162
1163 return true;
1164 }
1165
1166 struct FindClosestMatchingLayerDataForRecursion {
1167 FindClosestMatchingLayerDataForRecursion()
1168 : closest_match(NULL),
1169 closest_distance(-std::numeric_limits<float>::infinity()) {}
1170 LayerImpl* closest_match;
1171 // Note that the positive z-axis points towards the camera, so bigger means
1172 // closer in this case, counterintuitively.
1173 float closest_distance;
1174 };
1175
1176 template <typename Functor>
1177 static void FindClosestMatchingLayer(
1178 const gfx::PointF& screen_space_point,
1179 LayerImpl* layer,
1180 const Functor& func,
1181 FindClosestMatchingLayerDataForRecursion* data_for_recursion) {
1182 for (int i = layer->children().size() - 1; i >= 0; --i) {
1183 FindClosestMatchingLayer(
1184 screen_space_point, layer->children()[i], func, data_for_recursion);
1185 }
1186
1187 float distance_to_intersection = 0.f;
1188 if (func(layer) &&
1189 PointHitsLayer(layer, screen_space_point, &distance_to_intersection) &&
1190 ((!data_for_recursion->closest_match ||
1191 distance_to_intersection > data_for_recursion->closest_distance))) {
1192 data_for_recursion->closest_distance = distance_to_intersection;
1193 data_for_recursion->closest_match = layer;
1194 }
1195 }
1196
1197 static bool ScrollsAnyDrawnRenderSurfaceLayerListMember(LayerImpl* layer) {
1198 if (!layer->scrollable())
1199 return false;
1200 if (layer->IsDrawnRenderSurfaceLayerListMember())
1201 return true;
1202 if (!layer->scroll_children())
1203 return false;
1204 for (std::set<LayerImpl*>::const_iterator it =
1205 layer->scroll_children()->begin();
1206 it != layer->scroll_children()->end();
1207 ++it) {
1208 if ((*it)->IsDrawnRenderSurfaceLayerListMember())
1209 return true;
1210 }
1211 return false;
1212 }
1213
1214 struct FindScrollingLayerFunctor {
1215 bool operator()(LayerImpl* layer) const {
1216 return ScrollsAnyDrawnRenderSurfaceLayerListMember(layer);
1217 }
1218 };
1219
1220 LayerImpl* LayerTreeImpl::FindFirstScrollingLayerThatIsHitByPoint(
1221 const gfx::PointF& screen_space_point) {
1222 FindClosestMatchingLayerDataForRecursion data_for_recursion;
1223 FindClosestMatchingLayer(screen_space_point,
1224 root_layer(),
1225 FindScrollingLayerFunctor(),
1226 &data_for_recursion);
1227 return data_for_recursion.closest_match;
1228 }
1229
1230 struct HitTestVisibleScrollableOrTouchableFunctor {
1231 bool operator()(LayerImpl* layer) const {
1232 return layer->IsDrawnRenderSurfaceLayerListMember() ||
1233 ScrollsAnyDrawnRenderSurfaceLayerListMember(layer) ||
1234 !layer->touch_event_handler_region().IsEmpty() ||
1235 layer->have_wheel_event_handlers();
1236 }
1237 };
1238
1239 LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPoint(
1240 const gfx::PointF& screen_space_point) {
1241 FindClosestMatchingLayerDataForRecursion data_for_recursion;
1242 FindClosestMatchingLayer(screen_space_point,
1243 root_layer(),
1244 HitTestVisibleScrollableOrTouchableFunctor(),
1245 &data_for_recursion);
1246 return data_for_recursion.closest_match;
1247 }
1248
1249 static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point,
1250 LayerImpl* layer_impl) {
1251 if (layer_impl->touch_event_handler_region().IsEmpty())
1252 return false;
1253
1254 if (!PointHitsRegion(screen_space_point,
1255 layer_impl->screen_space_transform(),
1256 layer_impl->touch_event_handler_region(),
1257 layer_impl->contents_scale_x(),
1258 layer_impl->contents_scale_y()))
1259 return false;
1260
1261 // At this point, we think the point does hit the touch event handler region
1262 // on the layer, but we need to walk up the parents to ensure that the layer
1263 // was not clipped in such a way that the hit point actually should not hit
1264 // the layer.
1265 if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl))
1266 return false;
1267
1268 return true;
1269 }
1270
1271 struct FindTouchEventLayerFunctor {
1272 bool operator()(LayerImpl* layer) const {
1273 return LayerHasTouchEventHandlersAt(screen_space_point, layer);
1274 }
1275 const gfx::PointF screen_space_point;
1276 };
1277
1278 LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
1279 const gfx::PointF& screen_space_point) {
1280 FindTouchEventLayerFunctor func = {screen_space_point};
1281 FindClosestMatchingLayerDataForRecursion data_for_recursion;
1282 FindClosestMatchingLayer(
1283 screen_space_point, root_layer(), func, &data_for_recursion);
1284 return data_for_recursion.closest_match;
1285 }
1286
1025 } // namespace cc 1287 } // namespace cc
OLDNEW
« no previous file with comments | « cc/trees/layer_tree_impl.h ('k') | cc/trees/layer_tree_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698