blob: 7488dc6a3d5b6dfec57b024a168c80068289d158 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_COMMON_HIT_TEST_HIT_TEST_QUERY_H_
#define COMPONENTS_VIZ_COMMON_HIT_TEST_HIT_TEST_QUERY_H_
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/safe_ref.h"
#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
#include "components/viz/common/viz_common_export.h"
#include "ui/gfx/geometry/point_f.h"
namespace viz {
struct Target {
FrameSinkId frame_sink_id;
// Coordinates in the coordinate system of the target FrameSinkId.
gfx::PointF location_in_target;
// Different flags are defined in services/viz/public/mojom/hit_test/
// hit_test_region_list.mojom.
uint32_t flags = 0;
};
enum class EventSource {
MOUSE,
TOUCH,
ANY,
};
// Finds the target for a given location based on the AggregatedHitTestRegion
// list aggregated by HitTestAggregator.
// TODO(crbug.com/41460939): Handle 3d space cases correctly.
class VIZ_COMMON_EXPORT HitTestQuery {
public:
class DataProvider {
public:
virtual ~DataProvider() = default;
// Gets HitTestData from `HitTestAggregator` on VizCompositor thread.
virtual const std::vector<AggregatedHitTestRegion>& GetHitTestData()
const = 0;
};
explicit HitTestQuery(std::optional<base::SafeRef<DataProvider>> provider);
HitTestQuery(const HitTestQuery&) = delete;
HitTestQuery& operator=(const HitTestQuery&) = delete;
virtual ~HitTestQuery();
// HitTestAggregator has sent the most recent |hit_test_data| for targeting/
// transforming requests.
void OnAggregatedHitTestRegionListUpdated(
const std::vector<AggregatedHitTestRegion>& hit_test_data);
// Finds Target for |location_in_root|, including the FrameSinkId of the
// target, updated location in the coordinate system of the target and
// hit-test flags for the target.
// Assumptions about the AggregatedHitTestRegion list received.
// 1. The list is in ascending (front to back) z-order.
// 2. Children count includes children of children.
// 3. After applying transform to the incoming point, point is in the same
// coordinate system as the bounds it is comparing against. We shouldn't
// need to apply rect's origin offset as it should be included in this
// transform.
// For example,
// +e-------------+
// | +c---------|
// | 1 |+a--+ |
// | || 2 | |
// | |+b--------|
// | || |
// | || 3 |
// +--------------+
// In this case, after applying identity transform, 1 is in the coordinate
// system of e; apply the transfrom-from-e-to-c and transform-from-c-to-a
// then we get 2 in the coordinate system of a; apply the
// transfrom-from-e-to-c and transform-from-c-to-b then we get 3 in the
// coordinate system of b.
Target FindTargetForLocation(EventSource event_source,
const gfx::PointF& location_in_root) const;
// Same as FindTargetForLocation(), but starts from |frame_sink_id|.
// |location| is in the coordinate space of |frame_sink_id|. Returns an empty
// target if |frame_sink_id| is not found.
Target FindTargetForLocationStartingFrom(
EventSource event_source,
const gfx::PointF& location,
const FrameSinkId& frame_sink_id) const;
// When a target window is already known, e.g. capture/latched window, convert
// |location_in_root| to be in the coordinate space of the target and store
// that in |transformed_location|. Return true if the transform is successful
// and false otherwise.
// |target_ancestors| contains the FrameSinkId from target to root.
// |target_ancestors.front()| is the target, and |target_ancestors.back()|
// is the root.
bool TransformLocationForTarget(
const std::vector<FrameSinkId>& target_ancestors,
const gfx::PointF& location_in_root,
gfx::PointF* transformed_location) const;
// Gets the transform from root to |target| in physical pixels. Returns true
// and stores the result into |transform| if successful, returns false
// otherwise. This is potentially a little more expensive than
// TransformLocationForTarget(). So if the path from root to target is known,
// then that is the preferred API.
bool GetTransformToTarget(const FrameSinkId& target,
gfx::Transform* transform) const;
// Returns whether client has submitted hit test data for |frame_sink_id|.
// Note that this returns false even if the embedder has submitted hit-test
// data for |frame_sink_id|.
bool ContainsActiveFrameSinkId(const FrameSinkId& frame_sink_id) const;
// Returns hit-test data, using indentation to visualize the tree structure.
std::string PrintHitTestData() const;
const std::vector<AggregatedHitTestRegion>& GetHitTestData() const {
return hit_test_data_;
}
// Returns true if |id| is present in |hit_test_data|. If |id| is present
// |index| is set accordingly.
bool FindIndexOfFrameSink(const FrameSinkId& id, size_t* index) const;
protected:
// The FindTargetForLocation() functions call into this.
// If |is_location_relative_to_parent| is true, |location| is relative to
// the parent, otherwise it is in the coordinate space of |frame_sink_id|.
// Virtual for testing.
virtual Target FindTargetForLocationStartingFromImpl(
EventSource event_source,
const gfx::PointF& location,
const FrameSinkId& frame_sink_id,
bool is_location_relative_to_parent) const;
private:
// Helper function to find |target| for |location| in the |region_index|,
// returns true if a target is found and false otherwise. If
// |is_location_relative_to_parent| is true, |location| is in the coordinate
// space of |region_index|'s parent, otherwise it is in the coordinate space
// of |region_index|.
bool FindTargetInRegionForLocation(EventSource event_source,
const gfx::PointF& location,
size_t region_index,
bool is_location_relative_to_parent,
const FrameSinkId& root_view_frame_sink_id,
Target* target) const;
// Transform |location_in_target| to be in |region_index|'s coordinate space.
// |location_in_target| is in the coordinate space of |region_index|'s parent
// at the beginning.
bool TransformLocationForTargetRecursively(
const std::vector<FrameSinkId>& target_ancestors,
size_t target_ancestor,
size_t region_index,
gfx::PointF* location_in_target) const;
bool GetTransformToTargetRecursively(const FrameSinkId& target,
size_t region_index,
gfx::Transform* transform) const;
// Returns updated aggregated hit test data from stored `hit_test_data` in the
// browser and uses `provider_` to get updated hit test data on VizCompositor
// thread.
const std::vector<AggregatedHitTestRegion>& GetHitTestRegionData() const;
std::vector<AggregatedHitTestRegion> hit_test_data_;
// DataProvider is expected to outlive |this|. `HitTestAggregator` is the
// provider on VizCompositorThread whereas it's null on CrBrowserMain.
std::optional<base::SafeRef<DataProvider>> provider_;
};
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_HIT_TEST_HIT_TEST_QUERY_H_