OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/surfaces/surface_hittest.h" | |
6 | |
7 #include "cc/output/compositor_frame.h" | |
8 #include "cc/output/delegated_frame_data.h" | |
9 #include "cc/quads/draw_quad.h" | |
10 #include "cc/quads/render_pass_draw_quad.h" | |
11 #include "cc/quads/surface_draw_quad.h" | |
12 #include "cc/surfaces/surface.h" | |
13 #include "cc/surfaces/surface_manager.h" | |
14 #include "ui/gfx/geometry/point.h" | |
15 #include "ui/gfx/transform.h" | |
16 | |
17 namespace cc { | |
18 namespace { | |
19 const RenderPass* GetRootRenderPass(SurfaceManager* manager, | |
20 SurfaceId surface_id) { | |
21 Surface* surface = manager->GetSurfaceForId(surface_id); | |
22 | |
23 const CompositorFrame* surface_frame = surface->GetEligibleFrame(); | |
24 if (!surface_frame) | |
25 return nullptr; | |
26 | |
27 const DelegatedFrameData* frame_data = | |
28 surface_frame->delegated_frame_data.get(); | |
29 return frame_data->render_pass_list.empty() | |
30 ? nullptr | |
31 : frame_data->render_pass_list.back(); | |
32 } | |
33 } | |
34 | |
35 SurfaceHittest::SurfaceHittest(SurfaceManager* manager) : manager_(manager) {} | |
36 | |
37 SurfaceHittest::~SurfaceHittest() {} | |
38 | |
39 SurfaceId SurfaceHittest::Hittest(SurfaceId surface_id, | |
40 const gfx::Point& point, | |
41 gfx::Point* transformed_point) { | |
42 SurfaceId hittest_surface_id = surface_id; | |
43 | |
44 if (transformed_point) | |
45 *transformed_point = point; | |
46 | |
47 HittestInternal(surface_id, GetRootRenderPass(manager_, surface_id), point, | |
48 &hittest_surface_id, transformed_point); | |
49 | |
50 referenced_passes_.clear(); | |
51 | |
52 return hittest_surface_id; | |
53 } | |
54 | |
55 bool SurfaceHittest::HittestInternal(SurfaceId surface_id, | |
56 const RenderPass* render_pass, | |
57 const gfx::Point& point, | |
58 SurfaceId* out_surface_id, | |
59 gfx::Point* out_transformed_point) { | |
60 // To avoid an infinite recursion, we need to skip the RenderPass if it's | |
61 // already been referenced. | |
62 if (referenced_passes_.find(render_pass) != referenced_passes_.end()) | |
63 return false; | |
64 referenced_passes_.insert(render_pass); | |
65 | |
66 gfx::Transform transform_from_root_target; | |
67 if (!render_pass || | |
68 !render_pass->transform_to_root_target.GetInverse( | |
69 &transform_from_root_target)) { | |
70 return false; | |
71 } | |
72 | |
73 gfx::Point point_in_target_space(point); | |
74 transform_from_root_target.TransformPoint(&point_in_target_space); | |
75 | |
76 for (const auto* quad : render_pass->quad_list) { | |
77 // First we test against the clip_rect. The clip_rect is in target space, so | |
78 // we can test the point directly. | |
79 if (!quad->shared_quad_state->is_clipped || | |
80 quad->shared_quad_state->clip_rect.Contains(point_in_target_space)) { | |
81 // We now transform the point to content space and test if it hits the | |
82 // rect. | |
83 gfx::Transform target_to_quad_transform; | |
84 if (quad->shared_quad_state->quad_to_target_transform.GetInverse( | |
85 &target_to_quad_transform)) { | |
86 gfx::Point transformed_point(point_in_target_space); | |
87 target_to_quad_transform.TransformPoint(&transformed_point); | |
88 | |
89 if (quad->rect.Contains(transformed_point)) { | |
90 if (quad->material == DrawQuad::SURFACE_CONTENT) { | |
91 // We've hit a SurfaceDrawQuad, we need to recurse into this | |
92 // Surface. | |
93 const SurfaceDrawQuad* surface_quad = | |
94 SurfaceDrawQuad::MaterialCast(quad); | |
95 | |
96 gfx::Point point_in_current_surface; | |
97 if (out_transformed_point) { | |
98 point_in_current_surface = *out_transformed_point; | |
99 *out_transformed_point = transformed_point; | |
100 } | |
101 | |
102 if (HittestInternal( | |
103 surface_quad->surface_id, | |
104 GetRootRenderPass(manager_, surface_quad->surface_id), | |
105 transformed_point, out_surface_id, out_transformed_point)) { | |
106 return true; | |
107 } else { | |
108 if (out_transformed_point) | |
109 *out_transformed_point = point_in_current_surface; | |
110 } | |
111 } else if (quad->material == DrawQuad::RENDER_PASS) { | |
112 // We've hit a RenderPassDrawQuad, we need to recurse into this | |
113 // RenderPass. | |
114 const RenderPassDrawQuad* render_quad = | |
115 RenderPassDrawQuad::MaterialCast(quad); | |
116 | |
117 Surface* surface = manager_->GetSurfaceForId(surface_id); | |
118 const CompositorFrame* surface_frame = surface->GetEligibleFrame(); | |
119 DCHECK(surface_frame); | |
120 const DelegatedFrameData* frame_data = | |
121 surface_frame->delegated_frame_data.get(); | |
122 | |
123 const RenderPass* quad_render_pass = nullptr; | |
124 for (const auto* render_pass : frame_data->render_pass_list) { | |
125 if (render_pass->id == render_quad->render_pass_id) { | |
126 quad_render_pass = render_pass; | |
127 break; | |
128 } | |
129 } | |
jbauman
2015/08/06 20:42:19
Check if quad_render_pass is nullptr and don't do
lfg
2015/08/06 22:30:00
Done.
| |
130 | |
131 if (HittestInternal(surface_id, quad_render_pass, | |
132 point_in_target_space, out_surface_id, | |
133 out_transformed_point)) { | |
134 return true; | |
135 } | |
136 } else { | |
137 // We've hit a different type of quad in the current Surface, | |
138 // there's no need to iterate anymore, this is the quad that | |
139 // receives the event; | |
140 *out_surface_id = surface_id; | |
141 return true; | |
142 } | |
143 } | |
144 } | |
145 } | |
146 } | |
147 | |
148 return false; | |
149 } | |
150 } // namespace cc | |
OLD | NEW |