1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
// 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.
#include "components/viz/service/hit_test/hit_test_manager.h"
#include <utility>
#include <vector>
#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
#include "components/viz/service/hit_test/hit_test_aggregator.h"
#include "components/viz/service/surfaces/latest_local_surface_id_lookup_delegate.h"
#include "components/viz/service/surfaces/surface.h"
namespace viz {
namespace {
// TODO(gklassen): Review and select appropriate sizes based on
// telemetry / UMA.
constexpr uint32_t kMaxRegionsPerSurface = 1024;
// Whenever a hit test region is marked as kHitTestAsk there must be a reason
// for async hit test and vice versa.
bool FlagsAndAsyncReasonsMatch(uint32_t flags,
uint32_t async_hit_test_reasons) {
if (flags & kHitTestAsk)
return async_hit_test_reasons != kNotAsyncHitTest;
return async_hit_test_reasons == kNotAsyncHitTest;
}
} // namespace
HitTestManager::HitTestManager(SurfaceManager* surface_manager)
: surface_manager_(surface_manager) {}
HitTestManager::~HitTestManager() = default;
void HitTestManager::OnSurfaceDestroyed(const SurfaceId& surface_id) {
hit_test_region_lists_.erase(surface_id);
}
void HitTestManager::OnSurfaceActivated(const SurfaceId& surface_id) {
// When a Surface is activated we can confidently remove all
// associated HitTestRegionList objects with an older frame_index.
auto search = hit_test_region_lists_.find(surface_id);
if (search == hit_test_region_lists_.end())
return;
Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
DCHECK(surface);
uint64_t frame_index = surface->GetActiveFrameIndex();
auto& frame_index_map = search->second;
for (auto it = frame_index_map.begin(); it != frame_index_map.end();) {
if (it->first != frame_index)
it = frame_index_map.erase(it);
else
++it;
}
}
void HitTestManager::SubmitHitTestRegionList(
const SurfaceId& surface_id,
const uint64_t frame_index,
std::optional<HitTestRegionList> hit_test_region_list) {
if (!hit_test_region_list) {
auto& frame_index_map = hit_test_region_lists_[surface_id];
if (!frame_index_map.empty()) {
// We will reuse the last submitted hit-test data.
uint64_t last_frame_index = frame_index_map.rbegin()->first;
HitTestRegionList last_hit_test_region_list =
std::move(frame_index_map[last_frame_index]);
frame_index_map[frame_index] = std::move(last_hit_test_region_list);
frame_index_map.erase(last_frame_index);
}
return;
}
if (!ValidateHitTestRegionList(surface_id, &*hit_test_region_list))
return;
++submit_hit_test_region_list_index_;
// TODO(gklassen): Runtime validation that hit_test_region_list is valid.
// TODO(gklassen): Inform FrameSink that the hit_test_region_list is invalid.
// TODO(gklassen): FrameSink needs to inform the host of a difficult renderer.
hit_test_region_lists_[surface_id][frame_index] =
std::move(*hit_test_region_list);
}
const HitTestRegionList* HitTestManager::GetActiveHitTestRegionList(
LatestLocalSurfaceIdLookupDelegate* delegate,
const FrameSinkId& frame_sink_id,
uint64_t* store_active_frame_index) const {
if (!delegate)
return nullptr;
LocalSurfaceId local_surface_id =
delegate->GetSurfaceAtAggregation(frame_sink_id);
if (!local_surface_id.is_valid())
return nullptr;
SurfaceId surface_id(frame_sink_id, local_surface_id);
auto search = hit_test_region_lists_.find(surface_id);
if (search == hit_test_region_lists_.end())
return nullptr;
Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
DCHECK(surface);
uint64_t frame_index = surface->GetActiveFrameIndex();
if (store_active_frame_index)
*store_active_frame_index = frame_index;
auto& frame_index_map = search->second;
auto search2 = frame_index_map.find(frame_index);
if (search2 == frame_index_map.end())
return nullptr;
return &search2->second;
}
int64_t HitTestManager::GetTraceId(const SurfaceId& id) const {
Surface* surface = surface_manager_->GetSurfaceForId(id);
return surface->GetActiveFrameMetadata().begin_frame_ack.trace_id;
}
bool HitTestManager::ValidateHitTestRegionList(
const SurfaceId& surface_id,
HitTestRegionList* hit_test_region_list) {
if (hit_test_region_list->regions.size() > kMaxRegionsPerSurface)
return false;
if (!FlagsAndAsyncReasonsMatch(
hit_test_region_list->flags,
hit_test_region_list->async_hit_test_reasons)) {
return false;
}
for (auto& region : hit_test_region_list->regions) {
// TODO(gklassen): Ensure that |region->frame_sink_id| is a child of
// |frame_sink_id|.
if (region.frame_sink_id.client_id() == 0) {
region.frame_sink_id = FrameSinkId(surface_id.frame_sink_id().client_id(),
region.frame_sink_id.sink_id());
}
if (!FlagsAndAsyncReasonsMatch(region.flags, region.async_hit_test_reasons))
return false;
}
return true;
}
} // namespace viz
|