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