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