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

Side by Side Diff: cc/trees/layer_tree_host_common.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: Minor cleanups. 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
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_host_common.h" 5 #include "cc/trees/layer_tree_host_common.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "cc/base/math_util.h" 10 #include "cc/base/math_util.h"
11 #include "cc/layers/heads_up_display_layer_impl.h" 11 #include "cc/layers/heads_up_display_layer_impl.h"
12 #include "cc/layers/layer.h" 12 #include "cc/layers/layer.h"
13 #include "cc/layers/layer_impl.h" 13 #include "cc/layers/layer_impl.h"
14 #include "cc/layers/layer_iterator.h" 14 #include "cc/layers/layer_iterator.h"
15 #include "cc/layers/render_surface.h" 15 #include "cc/layers/render_surface.h"
16 #include "cc/layers/render_surface_impl.h" 16 #include "cc/layers/render_surface_impl.h"
17 #include "cc/trees/layer_sorter.h" 17 #include "cc/trees/layer_sorter.h"
18 #include "cc/trees/layer_tree_impl.h" 18 #include "cc/trees/layer_tree_impl.h"
19 #include "ui/gfx/point_conversions.h"
20 #include "ui/gfx/rect_conversions.h" 19 #include "ui/gfx/rect_conversions.h"
21 #include "ui/gfx/transform.h" 20 #include "ui/gfx/transform.h"
22 21
23 namespace cc { 22 namespace cc {
24 23
25 ScrollAndScaleSet::ScrollAndScaleSet() {} 24 ScrollAndScaleSet::ScrollAndScaleSet() {}
26 25
27 ScrollAndScaleSet::~ScrollAndScaleSet() {} 26 ScrollAndScaleSet::~ScrollAndScaleSet() {}
28 27
29 static void SortLayers(LayerList::iterator forst, 28 static void SortLayers(LayerList::iterator forst,
(...skipping 2390 matching lines...) Expand 10 before | Expand all | Expand 10 after
2420 &accumulated_surface_state, 2419 &accumulated_surface_state,
2421 inputs->current_render_surface_layer_list_id); 2420 inputs->current_render_surface_layer_list_id);
2422 2421
2423 // The dummy layer list should not have been used. 2422 // The dummy layer list should not have been used.
2424 DCHECK_EQ(0u, dummy_layer_list.size()); 2423 DCHECK_EQ(0u, dummy_layer_list.size());
2425 // A root layer render_surface should always exist after 2424 // A root layer render_surface should always exist after
2426 // CalculateDrawProperties. 2425 // CalculateDrawProperties.
2427 DCHECK(inputs->root_layer->render_surface()); 2426 DCHECK(inputs->root_layer->render_surface());
2428 } 2427 }
2429 2428
2430 static bool PointHitsRect(
2431 const gfx::PointF& screen_space_point,
2432 const gfx::Transform& local_space_to_screen_space_transform,
2433 const gfx::RectF& local_space_rect) {
2434 // If the transform is not invertible, then assume that this point doesn't hit
2435 // this rect.
2436 gfx::Transform inverse_local_space_to_screen_space(
2437 gfx::Transform::kSkipInitialization);
2438 if (!local_space_to_screen_space_transform.GetInverse(
2439 &inverse_local_space_to_screen_space))
2440 return false;
2441
2442 // Transform the hit test point from screen space to the local space of the
2443 // given rect.
2444 bool clipped = false;
2445 gfx::PointF hit_test_point_in_local_space = MathUtil::ProjectPoint(
2446 inverse_local_space_to_screen_space, screen_space_point, &clipped);
2447
2448 // If ProjectPoint could not project to a valid value, then we assume that
2449 // this point doesn't hit this rect.
2450 if (clipped)
2451 return false;
2452
2453 return local_space_rect.Contains(hit_test_point_in_local_space);
2454 }
2455
2456 static bool PointHitsRegion(const gfx::PointF& screen_space_point,
2457 const gfx::Transform& screen_space_transform,
2458 const Region& layer_space_region,
2459 float layer_content_scale_x,
2460 float layer_content_scale_y) {
2461 // If the transform is not invertible, then assume that this point doesn't hit
2462 // this region.
2463 gfx::Transform inverse_screen_space_transform(
2464 gfx::Transform::kSkipInitialization);
2465 if (!screen_space_transform.GetInverse(&inverse_screen_space_transform))
2466 return false;
2467
2468 // Transform the hit test point from screen space to the local space of the
2469 // given region.
2470 bool clipped = false;
2471 gfx::PointF hit_test_point_in_content_space = MathUtil::ProjectPoint(
2472 inverse_screen_space_transform, screen_space_point, &clipped);
2473 gfx::PointF hit_test_point_in_layer_space =
2474 gfx::ScalePoint(hit_test_point_in_content_space,
2475 1.f / layer_content_scale_x,
2476 1.f / layer_content_scale_y);
2477
2478 // If ProjectPoint could not project to a valid value, then we assume that
2479 // this point doesn't hit this region.
2480 if (clipped)
2481 return false;
2482
2483 return layer_space_region.Contains(
2484 gfx::ToRoundedPoint(hit_test_point_in_layer_space));
2485 }
2486
2487 static bool PointIsClippedBySurfaceOrClipRect(
2488 const gfx::PointF& screen_space_point,
2489 LayerImpl* layer) {
2490 LayerImpl* current_layer = layer;
2491
2492 // Walk up the layer tree and hit-test any render_surfaces and any layer
2493 // clip rects that are active.
2494 while (current_layer) {
2495 if (current_layer->render_surface() &&
2496 !PointHitsRect(
2497 screen_space_point,
2498 current_layer->render_surface()->screen_space_transform(),
2499 current_layer->render_surface()->content_rect()))
2500 return true;
2501
2502 // Note that drawable content rects are actually in target surface space, so
2503 // the transform we have to provide is the target surface's
2504 // screen_space_transform.
2505 LayerImpl* render_target = current_layer->render_target();
2506 if (LayerClipsSubtree(current_layer) &&
2507 !PointHitsRect(
2508 screen_space_point,
2509 render_target->render_surface()->screen_space_transform(),
2510 current_layer->drawable_content_rect()))
2511 return true;
2512
2513 current_layer = current_layer->parent();
2514 }
2515
2516 // If we have finished walking all ancestors without having already exited,
2517 // then the point is not clipped by any ancestors.
2518 return false;
2519 }
2520
2521 static bool PointHitsLayer(LayerImpl* layer,
2522 const gfx::PointF& screen_space_point) {
2523 gfx::RectF content_rect(layer->content_bounds());
2524 if (!PointHitsRect(
2525 screen_space_point, layer->screen_space_transform(), content_rect))
2526 return false;
2527
2528 // At this point, we think the point does hit the layer, but we need to walk
2529 // up the parents to ensure that the layer was not clipped in such a way
2530 // that the hit point actually should not hit the layer.
2531 if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer))
2532 return false;
2533
2534 // Skip the HUD layer.
2535 if (layer == layer->layer_tree_impl()->hud_layer())
2536 return false;
2537
2538 return true;
2539 }
2540
2541 LayerImpl* LayerTreeHostCommon::FindFirstScrollingLayerThatIsHitByPoint(
2542 const gfx::PointF& screen_space_point,
2543 const LayerImplList& render_surface_layer_list) {
2544 typedef LayerIterator<LayerImpl> LayerIteratorType;
2545 LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list);
2546 for (LayerIteratorType it =
2547 LayerIteratorType::Begin(&render_surface_layer_list);
2548 it != end;
2549 ++it) {
2550 // We don't want to consider render_surfaces for hit testing.
2551 if (!it.represents_itself())
2552 continue;
2553
2554 LayerImpl* current_layer = (*it);
2555 if (!PointHitsLayer(current_layer, screen_space_point))
2556 continue;
2557
2558 if (current_layer->scrollable())
2559 return current_layer;
2560 }
2561
2562 return NULL;
2563 }
2564
2565 LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPoint(
2566 const gfx::PointF& screen_space_point,
2567 const LayerImplList& render_surface_layer_list) {
2568 LayerImpl* found_layer = NULL;
2569
2570 typedef LayerIterator<LayerImpl> LayerIteratorType;
2571 LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list);
2572 for (LayerIteratorType
2573 it = LayerIteratorType::Begin(&render_surface_layer_list);
2574 it != end;
2575 ++it) {
2576 // We don't want to consider render_surfaces for hit testing.
2577 if (!it.represents_itself())
2578 continue;
2579
2580 LayerImpl* current_layer = (*it);
2581 if (!PointHitsLayer(current_layer, screen_space_point))
2582 continue;
2583
2584 found_layer = current_layer;
2585 break;
2586 }
2587
2588 // This can potentially return NULL, which means the screen_space_point did
2589 // not successfully hit test any layers, not even the root layer.
2590 return found_layer;
2591 }
2592
2593 LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
2594 const gfx::PointF& screen_space_point,
2595 const LayerImplList& render_surface_layer_list) {
2596 typedef LayerIterator<LayerImpl> LayerIteratorType;
2597 LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list);
2598 for (LayerIteratorType it =
2599 LayerIteratorType::Begin(&render_surface_layer_list);
2600 it != end;
2601 ++it) {
2602 // We don't want to consider render_surfaces for hit testing.
2603 if (!it.represents_itself())
2604 continue;
2605
2606 LayerImpl* current_layer = (*it);
2607 if (!PointHitsLayer(current_layer, screen_space_point))
2608 continue;
2609
2610 if (LayerTreeHostCommon::LayerHasTouchEventHandlersAt(screen_space_point,
2611 current_layer))
2612 return current_layer;
2613
2614 // Note that we could stop searching if we hit a layer we know to be
2615 // opaque to hit-testing, but knowing that reliably is tricky (eg. due to
2616 // CSS pointer-events: none). Also blink has an optimization for the
2617 // common case of an entire document having handlers where it doesn't
2618 // report any rects for child layers (since it knows they can't exceed
2619 // the document bounds).
2620 }
2621 return NULL;
2622 }
2623
2624 bool LayerTreeHostCommon::LayerHasTouchEventHandlersAt(
2625 const gfx::PointF& screen_space_point,
2626 LayerImpl* layer_impl) {
2627 if (layer_impl->touch_event_handler_region().IsEmpty())
2628 return false;
2629
2630 if (!PointHitsRegion(screen_space_point,
2631 layer_impl->screen_space_transform(),
2632 layer_impl->touch_event_handler_region(),
2633 layer_impl->contents_scale_x(),
2634 layer_impl->contents_scale_y()))
2635 return false;
2636
2637 // At this point, we think the point does hit the touch event handler region
2638 // on the layer, but we need to walk up the parents to ensure that the layer
2639 // was not clipped in such a way that the hit point actually should not hit
2640 // the layer.
2641 if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl))
2642 return false;
2643
2644 return true;
2645 }
2646 } // namespace cc 2429 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698