[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / cc / surfaces / surface_hittest.cc
blob89f4d3bd91d673339be761135187418376159247
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.
5 #include "cc/surfaces/surface_hittest.h"
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"
17 namespace cc {
18 namespace {
21 SurfaceHittest::SurfaceHittest(SurfaceManager* manager) : manager_(manager) {}
23 SurfaceHittest::~SurfaceHittest() {}
25 SurfaceId SurfaceHittest::GetTargetSurfaceAtPoint(
26 SurfaceId surface_id,
27 const gfx::Point& point,
28 gfx::Point* transformed_point) {
29 SurfaceId hittest_surface_id = surface_id;
31 if (transformed_point)
32 *transformed_point = point;
34 std::set<const RenderPass*> referenced_passes;
35 GetTargetSurfaceAtPointInternal(surface_id, RenderPassId(), point,
36 &referenced_passes, &hittest_surface_id,
37 transformed_point);
39 return hittest_surface_id;
42 bool SurfaceHittest::GetTargetSurfaceAtPointInternal(
43 SurfaceId surface_id,
44 const RenderPassId& render_pass_id,
45 const gfx::Point& point_in_root_target,
46 std::set<const RenderPass*>* referenced_passes,
47 SurfaceId* out_surface_id,
48 gfx::Point* out_transformed_point) {
49 const RenderPass* render_pass =
50 GetRenderPassForSurfaceById(surface_id, render_pass_id);
51 if (!render_pass)
52 return false;
54 // To avoid an infinite recursion, we need to skip the RenderPass if it's
55 // already been referenced.
56 if (referenced_passes->find(render_pass) != referenced_passes->end())
57 return false;
59 referenced_passes->insert(render_pass);
61 // The |transform_to_root_target| matrix cannot be inverted if it has a
62 // z-scale of 0 or due to floating point errors.
63 gfx::Transform transform_from_root_target;
64 if (!render_pass->transform_to_root_target.GetInverse(
65 &transform_from_root_target)) {
66 return false;
69 gfx::Point point_in_render_pass_space(point_in_root_target);
70 transform_from_root_target.TransformPoint(&point_in_render_pass_space);
72 for (const DrawQuad* quad : render_pass->quad_list) {
73 gfx::Point point_in_quad_space;
74 if (!PointInQuad(quad, point_in_render_pass_space, &point_in_quad_space))
75 continue;
77 if (quad->material == DrawQuad::SURFACE_CONTENT) {
78 // We've hit a SurfaceDrawQuad, we need to recurse into this
79 // Surface.
80 const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
82 gfx::Point point_in_child_space(point_in_quad_space);
83 if (GetTargetSurfaceAtPointInternal(
84 surface_quad->surface_id, RenderPassId(), point_in_quad_space,
85 referenced_passes, out_surface_id, &point_in_child_space)) {
86 *out_transformed_point = point_in_child_space;
87 return true;
90 continue;
93 if (quad->material == DrawQuad::RENDER_PASS) {
94 // We've hit a RenderPassDrawQuad, we need to recurse into this
95 // RenderPass.
96 const RenderPassDrawQuad* render_quad =
97 RenderPassDrawQuad::MaterialCast(quad);
99 gfx::Point point_in_child_space(point_in_root_target);
100 if (GetTargetSurfaceAtPointInternal(
101 surface_id, render_quad->render_pass_id, point_in_root_target,
102 referenced_passes, out_surface_id, &point_in_child_space)) {
103 *out_transformed_point = point_in_child_space;
104 return true;
107 continue;
110 // We've hit a different type of quad in the current Surface,
111 // there's no need to iterate anymore, this is the quad that
112 // receives the event;
113 *out_surface_id = surface_id;
114 return true;
117 // No quads were found beneath the provided |point|.
118 return false;
121 const RenderPass* SurfaceHittest::GetRenderPassForSurfaceById(
122 SurfaceId surface_id,
123 const RenderPassId& render_pass_id) {
124 Surface* surface = manager_->GetSurfaceForId(surface_id);
125 if (!surface)
126 return nullptr;
128 const CompositorFrame* surface_frame = surface->GetEligibleFrame();
129 if (!surface_frame)
130 return nullptr;
132 const DelegatedFrameData* frame_data =
133 surface_frame->delegated_frame_data.get();
134 if (frame_data->render_pass_list.empty())
135 return nullptr;
137 if (!render_pass_id.IsValid())
138 return frame_data->render_pass_list.back();
140 for (const auto* render_pass : frame_data->render_pass_list) {
141 if (render_pass->id == render_pass_id)
142 return render_pass;
145 return nullptr;
148 bool SurfaceHittest::PointInQuad(const DrawQuad* quad,
149 const gfx::Point& point_in_render_pass_space,
150 gfx::Point* point_in_quad_space) {
151 // First we test against the clip_rect. The clip_rect is in target space, so
152 // we can test the point directly.
153 if (quad->shared_quad_state->is_clipped &&
154 !quad->shared_quad_state->clip_rect.Contains(
155 point_in_render_pass_space)) {
156 return false;
159 // We now transform the point to content space and test if it hits the
160 // rect.
161 gfx::Transform target_to_quad_transform;
162 if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
163 &target_to_quad_transform)) {
164 return false;
167 *point_in_quad_space = point_in_render_pass_space;
168 target_to_quad_transform.TransformPoint(point_in_quad_space);
170 return quad->rect.Contains(*point_in_quad_space);
173 } // namespace cc