mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1666641 - Build hit-testing structure from clip templates. r=nical
Previously, the hit-testing structure was built from the set of clip-chains supplied to the frame builder, but this has several disadvantages. Now, the hit-testing structure is built during scene building, flattening clip templates into a set of clips that applies to each hit-testing primitive. The advantages are: - Most importantly, hit-testing doesn't rely on the existing clip-chain code, allowing changes and optimizations to that. - No need to read all of the clips for the entire scene, only clips that are referenced by hit-test items are read (which is typically a small fraction). - No need to read the clips each time the hit-tester is rebuilt, during frame building. Instead, the clips are read only once during each scene build. - Clips are stored in the hit testing scene, and thus shared among all hit-testers created for a given scene. Differential Revision: https://phabricator.services.mozilla.com/D91067
This commit is contained in:
parent
bd0e9ab215
commit
87ee371a3b
@ -155,7 +155,7 @@ pub struct SceneClipInstance {
|
||||
/// The interned clip + positioning information that is used during frame building.
|
||||
pub clip: ClipInstance,
|
||||
/// The definition of the clip, used during scene building to optimize clip-chains.
|
||||
pub key: ClipItemKeyKind,
|
||||
pub key: ClipItemKey,
|
||||
}
|
||||
|
||||
/// A clip template defines clips in terms of the public API. Specifically,
|
||||
@ -704,7 +704,7 @@ pub struct ClipStore {
|
||||
|
||||
/// Map of all clip templates defined by the public API to templates
|
||||
#[ignore_malloc_size_of = "range missing"]
|
||||
templates: FastHashMap<ClipId, ClipTemplate>,
|
||||
pub templates: FastHashMap<ClipId, ClipTemplate>,
|
||||
|
||||
/// A stack of current clip-chain builders. A new clip-chain builder is
|
||||
/// typically created each time a clip root (such as an iframe or stacking
|
||||
@ -1378,7 +1378,7 @@ impl ClipItemKeyKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
|
||||
#[derive(Debug, Copy, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct ClipItemKey {
|
||||
|
@ -3,13 +3,12 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::{BorderRadius, ClipMode, HitTestItem, HitTestResult, ItemTag, PrimitiveFlags};
|
||||
use api::{PipelineId, ApiHitTester};
|
||||
use api::{PipelineId, ApiHitTester, ClipId};
|
||||
use api::units::*;
|
||||
use crate::clip::{ClipChainId, ClipDataStore, ClipNode, ClipItemKind, ClipStore};
|
||||
use crate::clip::{rounded_rectangle_contains_point};
|
||||
use crate::clip::{ClipItemKind, ClipStore, ClipNode, rounded_rectangle_contains_point};
|
||||
use crate::spatial_tree::{SpatialNodeIndex, SpatialTree};
|
||||
use crate::internal_types::{FastHashMap, LayoutPrimitiveInfo};
|
||||
use std::{ops, u32};
|
||||
use std::ops;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use crate::util::LayoutToWorldFastTransform;
|
||||
|
||||
@ -52,7 +51,7 @@ impl ApiHitTester for SharedHitTester {
|
||||
/// data from the SpatialTree that will persist as a new frame is under construction,
|
||||
/// allowing hit tests consistent with the currently rendered frame.
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct HitTestSpatialNode {
|
||||
struct HitTestSpatialNode {
|
||||
/// The pipeline id of this node.
|
||||
pipeline_id: PipelineId,
|
||||
|
||||
@ -67,14 +66,19 @@ pub struct HitTestSpatialNode {
|
||||
}
|
||||
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct HitTestClipNode {
|
||||
struct HitTestClipNode {
|
||||
/// A particular point must be inside all of these regions to be considered clipped in
|
||||
/// for the purposes of a hit test.
|
||||
region: HitTestRegion,
|
||||
/// The positioning node for this clip
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
}
|
||||
|
||||
impl HitTestClipNode {
|
||||
fn new(node: &ClipNode) -> Self {
|
||||
fn new(
|
||||
node: ClipNode,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
) -> Self {
|
||||
let region = match node.item.kind {
|
||||
ClipItemKind::Rectangle { rect, mode } => {
|
||||
HitTestRegion::Rectangle(rect, mode)
|
||||
@ -90,50 +94,28 @@ impl HitTestClipNode {
|
||||
|
||||
HitTestClipNode {
|
||||
region,
|
||||
spatial_node_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Eq, Hash)]
|
||||
pub struct HitTestClipChainId(u32);
|
||||
|
||||
impl HitTestClipChainId {
|
||||
pub const NONE: Self = HitTestClipChainId(u32::MAX);
|
||||
}
|
||||
|
||||
/// A hit testing clip chain node is the same as a
|
||||
/// normal clip chain node, except that the clip
|
||||
/// node is embedded inside the clip chain, rather
|
||||
/// than referenced. This means we don't need to
|
||||
/// copy the complete interned clip data store for
|
||||
/// hit testing.
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct HitTestClipChainNode {
|
||||
pub region: HitTestClipNode,
|
||||
pub spatial_node_index: SpatialNodeIndex,
|
||||
pub parent_clip_chain_id: HitTestClipChainId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, MallocSizeOf)]
|
||||
pub struct HitTestingClipChainIndex(u32);
|
||||
|
||||
#[derive(Clone, MallocSizeOf)]
|
||||
pub struct HitTestingItem {
|
||||
struct HitTestingItem {
|
||||
rect: LayoutRect,
|
||||
clip_rect: LayoutRect,
|
||||
tag: ItemTag,
|
||||
is_backface_visible: bool,
|
||||
#[ignore_malloc_size_of = "simple"]
|
||||
clip_chain_range: ops::Range<HitTestingClipChainIndex>,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
#[ignore_malloc_size_of = "Range"]
|
||||
clip_nodes_range: ops::Range<ClipNodeIndex>,
|
||||
}
|
||||
|
||||
impl HitTestingItem {
|
||||
pub fn new(
|
||||
fn new(
|
||||
tag: ItemTag,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_chain_range: ops::Range<HitTestingClipChainIndex>,
|
||||
clip_nodes_range: ops::Range<ClipNodeIndex>,
|
||||
) -> HitTestingItem {
|
||||
HitTestingItem {
|
||||
rect: info.rect,
|
||||
@ -141,7 +123,7 @@ impl HitTestingItem {
|
||||
tag,
|
||||
is_backface_visible: info.flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE),
|
||||
spatial_node_index,
|
||||
clip_chain_range,
|
||||
clip_nodes_range,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,19 +131,22 @@ impl HitTestingItem {
|
||||
/// Statistics about allocation sizes of current hit tester,
|
||||
/// used to pre-allocate size of the next hit tester.
|
||||
pub struct HitTestingSceneStats {
|
||||
pub clip_chain_roots_count: usize,
|
||||
pub clip_nodes_count: usize,
|
||||
pub items_count: usize,
|
||||
}
|
||||
|
||||
impl HitTestingSceneStats {
|
||||
pub fn empty() -> Self {
|
||||
HitTestingSceneStats {
|
||||
clip_chain_roots_count: 0,
|
||||
clip_nodes_count: 0,
|
||||
items_count: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(MallocSizeOf, Debug, Copy, Clone)]
|
||||
pub struct ClipNodeIndex(u32);
|
||||
|
||||
/// Defines the immutable part of a hit tester for a given scene.
|
||||
/// The hit tester is recreated each time a frame is built, since
|
||||
/// it relies on the current values of the spatial tree.
|
||||
@ -170,11 +155,15 @@ impl HitTestingSceneStats {
|
||||
/// hit tester instances via Arc.
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct HitTestingScene {
|
||||
/// The list of variable clip chain roots referenced by the items.
|
||||
pub clip_chain_roots: Vec<HitTestClipChainId>,
|
||||
/// Packed array of all hit test clip nodes
|
||||
clip_nodes: Vec<HitTestClipNode>,
|
||||
|
||||
/// List of hit testing primitives.
|
||||
pub items: Vec<HitTestingItem>,
|
||||
items: Vec<HitTestingItem>,
|
||||
|
||||
/// Current stack of clip ids from stacking context
|
||||
#[ignore_malloc_size_of = "ClipId"]
|
||||
clip_id_stack: Vec<ClipId>,
|
||||
}
|
||||
|
||||
impl HitTestingScene {
|
||||
@ -182,39 +171,75 @@ impl HitTestingScene {
|
||||
/// provided by previous scene stats.
|
||||
pub fn new(stats: &HitTestingSceneStats) -> Self {
|
||||
HitTestingScene {
|
||||
clip_chain_roots: Vec::with_capacity(stats.clip_chain_roots_count),
|
||||
clip_nodes: Vec::with_capacity(stats.clip_nodes_count),
|
||||
items: Vec::with_capacity(stats.items_count),
|
||||
clip_id_stack: Vec::with_capacity(8),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get stats about the current scene allocation sizes.
|
||||
pub fn get_stats(&self) -> HitTestingSceneStats {
|
||||
HitTestingSceneStats {
|
||||
clip_chain_roots_count: self.clip_chain_roots.len(),
|
||||
clip_nodes_count: self.clip_nodes.len(),
|
||||
items_count: self.items.len(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a hit testing primitive.
|
||||
pub fn add_item(&mut self, item: HitTestingItem) {
|
||||
pub fn add_item(
|
||||
&mut self,
|
||||
tag: ItemTag,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_id: ClipId,
|
||||
clip_store: &ClipStore,
|
||||
) {
|
||||
let start = ClipNodeIndex(self.clip_nodes.len() as u32);
|
||||
|
||||
// Flatten all clips from the stacking context hierarchy
|
||||
for clip_id in &self.clip_id_stack {
|
||||
add_clips(
|
||||
*clip_id,
|
||||
clip_store,
|
||||
&mut self.clip_nodes,
|
||||
);
|
||||
}
|
||||
|
||||
// Add the primitive clip
|
||||
add_clips(
|
||||
clip_id,
|
||||
clip_store,
|
||||
&mut self.clip_nodes,
|
||||
);
|
||||
|
||||
let end = ClipNodeIndex(self.clip_nodes.len() as u32);
|
||||
|
||||
let item = HitTestingItem::new(
|
||||
tag,
|
||||
info,
|
||||
spatial_node_index,
|
||||
ops::Range {
|
||||
start,
|
||||
end,
|
||||
},
|
||||
);
|
||||
|
||||
self.items.push(item);
|
||||
}
|
||||
|
||||
/// Add a clip chain to the clip chain roots list.
|
||||
pub fn add_clip_chain(&mut self, clip_chain_id: ClipChainId) {
|
||||
if clip_chain_id != ClipChainId::INVALID {
|
||||
self.clip_chain_roots.push(HitTestClipChainId(clip_chain_id.0));
|
||||
}
|
||||
/// Push a clip onto the current stack
|
||||
pub fn push_clip(
|
||||
&mut self,
|
||||
clip_id: ClipId,
|
||||
) {
|
||||
self.clip_id_stack.push(clip_id);
|
||||
}
|
||||
|
||||
/// Get the slice of clip chain roots for a given hit test primitive.
|
||||
fn get_clip_chains_for_item(&self, item: &HitTestingItem) -> &[HitTestClipChainId] {
|
||||
&self.clip_chain_roots[item.clip_chain_range.start.0 as usize .. item.clip_chain_range.end.0 as usize]
|
||||
}
|
||||
|
||||
/// Get the next index of the clip chain roots list.
|
||||
pub fn next_clip_chain_index(&self) -> HitTestingClipChainIndex {
|
||||
HitTestingClipChainIndex(self.clip_chain_roots.len() as u32)
|
||||
/// Pop a clip from the current stack
|
||||
pub fn pop_clip(
|
||||
&mut self,
|
||||
) {
|
||||
self.clip_id_stack.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,7 +271,6 @@ pub struct HitTester {
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
scene: Arc<HitTestingScene>,
|
||||
spatial_nodes: Vec<HitTestSpatialNode>,
|
||||
clip_chains: Vec<HitTestClipChainNode>,
|
||||
pipeline_root_nodes: FastHashMap<PipelineId, SpatialNodeIndex>,
|
||||
}
|
||||
|
||||
@ -255,7 +279,6 @@ impl HitTester {
|
||||
HitTester {
|
||||
scene: Arc::new(HitTestingScene::new(&HitTestingSceneStats::empty())),
|
||||
spatial_nodes: Vec::new(),
|
||||
clip_chains: Vec::new(),
|
||||
pipeline_root_nodes: FastHashMap::default(),
|
||||
}
|
||||
}
|
||||
@ -263,31 +286,21 @@ impl HitTester {
|
||||
pub fn new(
|
||||
scene: Arc<HitTestingScene>,
|
||||
spatial_tree: &SpatialTree,
|
||||
clip_store: &ClipStore,
|
||||
clip_data_store: &ClipDataStore,
|
||||
) -> HitTester {
|
||||
let mut hit_tester = HitTester {
|
||||
scene,
|
||||
spatial_nodes: Vec::new(),
|
||||
clip_chains: Vec::new(),
|
||||
pipeline_root_nodes: FastHashMap::default(),
|
||||
};
|
||||
hit_tester.read_spatial_tree(
|
||||
spatial_tree,
|
||||
clip_store,
|
||||
clip_data_store,
|
||||
);
|
||||
hit_tester.read_spatial_tree(spatial_tree);
|
||||
hit_tester
|
||||
}
|
||||
|
||||
fn read_spatial_tree(
|
||||
&mut self,
|
||||
spatial_tree: &SpatialTree,
|
||||
clip_store: &ClipStore,
|
||||
clip_data_store: &ClipDataStore,
|
||||
) {
|
||||
self.spatial_nodes.clear();
|
||||
self.clip_chains.clear();
|
||||
|
||||
self.spatial_nodes.reserve(spatial_tree.spatial_nodes.len());
|
||||
for (index, node) in spatial_tree.spatial_nodes.iter().enumerate() {
|
||||
@ -312,97 +325,11 @@ impl HitTester {
|
||||
external_scroll_offset: spatial_tree.external_scroll_offset(index),
|
||||
});
|
||||
}
|
||||
|
||||
// For each clip chain node, extract the clip node from the clip
|
||||
// data store, and store it inline with the clip chain node.
|
||||
self.clip_chains.reserve(clip_store.clip_chain_nodes.len());
|
||||
for node in &clip_store.clip_chain_nodes {
|
||||
let clip_node = &clip_data_store[node.handle];
|
||||
self.clip_chains.push(HitTestClipChainNode {
|
||||
region: HitTestClipNode::new(clip_node),
|
||||
spatial_node_index: node.spatial_node_index,
|
||||
parent_clip_chain_id: HitTestClipChainId(node.parent_clip_chain_id.0),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn is_point_clipped_in_for_clip_chain(
|
||||
&self,
|
||||
point: WorldPoint,
|
||||
clip_chain_id: HitTestClipChainId,
|
||||
test: &mut HitTest
|
||||
) -> bool {
|
||||
if clip_chain_id == HitTestClipChainId::NONE {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(result) = test.get_from_clip_chain_cache(clip_chain_id) {
|
||||
return result == ClippedIn::ClippedIn;
|
||||
}
|
||||
|
||||
let descriptor = &self.clip_chains[clip_chain_id.0 as usize];
|
||||
let parent_clipped_in = self.is_point_clipped_in_for_clip_chain(
|
||||
point,
|
||||
descriptor.parent_clip_chain_id,
|
||||
test,
|
||||
);
|
||||
|
||||
if !parent_clipped_in {
|
||||
test.set_in_clip_chain_cache(clip_chain_id, ClippedIn::NotClippedIn);
|
||||
return false;
|
||||
}
|
||||
|
||||
if !self.is_point_clipped_in_for_clip_node(
|
||||
point,
|
||||
clip_chain_id,
|
||||
descriptor.spatial_node_index,
|
||||
test,
|
||||
) {
|
||||
test.set_in_clip_chain_cache(clip_chain_id, ClippedIn::NotClippedIn);
|
||||
return false;
|
||||
}
|
||||
|
||||
test.set_in_clip_chain_cache(clip_chain_id, ClippedIn::ClippedIn);
|
||||
true
|
||||
}
|
||||
|
||||
fn is_point_clipped_in_for_clip_node(
|
||||
&self,
|
||||
point: WorldPoint,
|
||||
clip_chain_node_id: HitTestClipChainId,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
test: &mut HitTest
|
||||
) -> bool {
|
||||
if let Some(clipped_in) = test.node_cache.get(&clip_chain_node_id) {
|
||||
return *clipped_in == ClippedIn::ClippedIn;
|
||||
}
|
||||
|
||||
let node = &self.clip_chains[clip_chain_node_id.0 as usize].region;
|
||||
let transform = self
|
||||
.spatial_nodes[spatial_node_index.0 as usize]
|
||||
.world_content_transform;
|
||||
let transformed_point = match transform
|
||||
.inverse()
|
||||
.and_then(|inverted| inverted.transform_point2d(point))
|
||||
{
|
||||
Some(point) => point,
|
||||
None => {
|
||||
test.node_cache.insert(clip_chain_node_id, ClippedIn::NotClippedIn);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if !node.region.contains(&transformed_point) {
|
||||
test.node_cache.insert(clip_chain_node_id, ClippedIn::NotClippedIn);
|
||||
return false;
|
||||
}
|
||||
|
||||
test.node_cache.insert(clip_chain_node_id, ClippedIn::ClippedIn);
|
||||
true
|
||||
}
|
||||
|
||||
pub fn hit_test(&self, mut test: HitTest) -> HitTestResult {
|
||||
pub fn hit_test(&self, test: HitTest) -> HitTestResult {
|
||||
let mut result = HitTestResult::default();
|
||||
|
||||
let mut current_spatial_node_index = SpatialNodeIndex::INVALID;
|
||||
let mut point_in_layer = None;
|
||||
let mut current_root_spatial_node_index = SpatialNodeIndex::INVALID;
|
||||
@ -438,12 +365,23 @@ impl HitTester {
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if any of the clip chain roots for this primitive
|
||||
// cull out the item.
|
||||
let clip_chains = self.scene.get_clip_chains_for_item(item);
|
||||
// See if any of the clips for this primitive cull out the item.
|
||||
let mut is_valid = true;
|
||||
for clip_chain_id in clip_chains {
|
||||
if !self.is_point_clipped_in_for_clip_chain(test.point, *clip_chain_id, &mut test) {
|
||||
let clip_nodes = &self.scene.clip_nodes[item.clip_nodes_range.start.0 as usize .. item.clip_nodes_range.end.0 as usize];
|
||||
for clip_node in clip_nodes {
|
||||
let transform = self
|
||||
.spatial_nodes[clip_node.spatial_node_index.0 as usize]
|
||||
.world_content_transform;
|
||||
let transformed_point = match transform
|
||||
.inverse()
|
||||
.and_then(|inverted| inverted.transform_point2d(test.point))
|
||||
{
|
||||
Some(point) => point,
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if !clip_node.region.contains(&transformed_point) {
|
||||
is_valid = false;
|
||||
break;
|
||||
}
|
||||
@ -489,18 +427,10 @@ impl HitTester {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
|
||||
enum ClippedIn {
|
||||
ClippedIn,
|
||||
NotClippedIn,
|
||||
}
|
||||
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct HitTest {
|
||||
pipeline_id: Option<PipelineId>,
|
||||
point: WorldPoint,
|
||||
node_cache: FastHashMap<HitTestClipChainId, ClippedIn>,
|
||||
clip_chain_cache: Vec<Option<ClippedIn>>,
|
||||
}
|
||||
|
||||
impl HitTest {
|
||||
@ -511,25 +441,34 @@ impl HitTest {
|
||||
HitTest {
|
||||
pipeline_id,
|
||||
point,
|
||||
node_cache: FastHashMap::default(),
|
||||
clip_chain_cache: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_from_clip_chain_cache(&mut self, index: HitTestClipChainId) -> Option<ClippedIn> {
|
||||
let index = index.0 as usize;
|
||||
if index >= self.clip_chain_cache.len() {
|
||||
None
|
||||
} else {
|
||||
self.clip_chain_cache[index]
|
||||
}
|
||||
}
|
||||
|
||||
fn set_in_clip_chain_cache(&mut self, index: HitTestClipChainId, value: ClippedIn) {
|
||||
let index = index.0 as usize;
|
||||
if index >= self.clip_chain_cache.len() {
|
||||
self.clip_chain_cache.resize(index + 1, None);
|
||||
}
|
||||
self.clip_chain_cache[index] = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect clips for a given ClipId, convert and add them to the hit testing
|
||||
/// scene, if not already present.
|
||||
fn add_clips(
|
||||
clip_id: ClipId,
|
||||
clip_store: &ClipStore,
|
||||
clip_nodes: &mut Vec<HitTestClipNode>,
|
||||
) {
|
||||
let template = &clip_store.templates[&clip_id];
|
||||
|
||||
for clip in &template.clips {
|
||||
let hit_test_clip_node = HitTestClipNode::new(
|
||||
clip.key.into(),
|
||||
clip.clip.spatial_node_index,
|
||||
);
|
||||
|
||||
clip_nodes.push(hit_test_clip_node);
|
||||
}
|
||||
|
||||
// The ClipId parenting is terminated when we reach the root ClipId
|
||||
if clip_id != template.parent {
|
||||
add_clips(
|
||||
template.parent,
|
||||
clip_store,
|
||||
clip_nodes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -663,7 +663,7 @@ impl Document {
|
||||
&self.dynamic_properties,
|
||||
);
|
||||
|
||||
let hit_tester = Arc::new(self.scene.create_hit_tester(&self.data_stores.clip));
|
||||
let hit_tester = Arc::new(self.scene.create_hit_tester());
|
||||
self.hit_tester = Some(Arc::clone(&hit_tester));
|
||||
self.shared_hit_tester.update(hit_tester);
|
||||
self.hit_tester_is_valid = true;
|
||||
|
@ -8,7 +8,7 @@ use api::units::*;
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use crate::render_api::MemoryReport;
|
||||
use crate::composite::CompositorKind;
|
||||
use crate::clip::{ClipStore, ClipDataStore};
|
||||
use crate::clip::ClipStore;
|
||||
use crate::spatial_tree::SpatialTree;
|
||||
use crate::frame_builder::{ChasePrimitive, FrameBuilderConfig};
|
||||
use crate::hit_test::{HitTester, HitTestingScene, HitTestingSceneStats};
|
||||
@ -320,15 +320,10 @@ impl BuiltScene {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_hit_tester(
|
||||
&mut self,
|
||||
clip_data_store: &ClipDataStore,
|
||||
) -> HitTester {
|
||||
pub fn create_hit_tester(&mut self) -> HitTester {
|
||||
HitTester::new(
|
||||
Arc::clone(&self.hit_testing_scene),
|
||||
&self.spatial_tree,
|
||||
&self.clip_store,
|
||||
clip_data_store,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use crate::clip::{ClipInternData, ClipNodeKind, ClipInstance, SceneClipInstance}
|
||||
use crate::spatial_tree::{ROOT_SPATIAL_NODE_INDEX, SpatialTree, SpatialNodeIndex};
|
||||
use crate::frame_builder::{ChasePrimitive, FrameBuilderConfig};
|
||||
use crate::glyph_rasterizer::FontInstance;
|
||||
use crate::hit_test::{HitTestingItem, HitTestingScene};
|
||||
use crate::hit_test::HitTestingScene;
|
||||
use crate::intern::Interner;
|
||||
use crate::internal_types::{FastHashMap, LayoutPrimitiveInfo, Filter};
|
||||
use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureOptions};
|
||||
@ -42,7 +42,7 @@ use crate::space::SpaceSnapper;
|
||||
use crate::spatial_node::{StickyFrameInfo, ScrollFrameKind};
|
||||
use crate::tile_cache::TileCacheBuilder;
|
||||
use euclid::approxeq::ApproxEq;
|
||||
use std::{f32, mem, usize, ops};
|
||||
use std::{f32, mem, usize};
|
||||
use std::collections::vec_deque::VecDeque;
|
||||
use std::sync::Arc;
|
||||
use crate::util::{MaxRect, VecHelper};
|
||||
@ -931,7 +931,9 @@ impl<'a> SceneBuilder<'a> {
|
||||
DisplayItem::HitTest(ref info) => {
|
||||
profile_scope!("hit_test");
|
||||
|
||||
let (layout, _, spatial_node_index, clip_chain_id) = self.process_common_properties(
|
||||
// TODO(gw): We could skip building the clip-chain here completely, as it's not used by
|
||||
// hit-test items.
|
||||
let (layout, _, spatial_node_index, _) = self.process_common_properties(
|
||||
&info.common,
|
||||
None,
|
||||
);
|
||||
@ -942,7 +944,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
self.add_primitive_to_hit_testing_list(
|
||||
&layout,
|
||||
spatial_node_index,
|
||||
clip_chain_id,
|
||||
info.common.clip_id,
|
||||
info.tag,
|
||||
);
|
||||
}
|
||||
@ -1352,37 +1354,16 @@ impl<'a> SceneBuilder<'a> {
|
||||
&mut self,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_chain_id: ClipChainId,
|
||||
clip_id: ClipId,
|
||||
tag: ItemTag,
|
||||
) {
|
||||
// We want to get a range of clip chain roots that apply to this
|
||||
// hit testing primitive.
|
||||
|
||||
// Get the start index for the clip chain root range for this primitive.
|
||||
let start = self.hit_testing_scene.next_clip_chain_index();
|
||||
|
||||
// Add the clip chain root for the primitive itself.
|
||||
self.hit_testing_scene.add_clip_chain(clip_chain_id);
|
||||
|
||||
// Append any clip chain roots from enclosing stacking contexts.
|
||||
for sc in &self.sc_stack {
|
||||
self.hit_testing_scene.add_clip_chain(sc.clip_chain_id);
|
||||
}
|
||||
|
||||
// Construct a clip chain roots range to be stored with the item.
|
||||
let clip_chain_range = ops::Range {
|
||||
start,
|
||||
end: self.hit_testing_scene.next_clip_chain_index(),
|
||||
};
|
||||
|
||||
// Create and store the hit testing primitive itself.
|
||||
let new_item = HitTestingItem::new(
|
||||
self.hit_testing_scene.add_item(
|
||||
tag,
|
||||
info,
|
||||
spatial_node_index,
|
||||
clip_chain_range,
|
||||
clip_id,
|
||||
&self.clip_store,
|
||||
);
|
||||
self.hit_testing_scene.add_item(new_item);
|
||||
}
|
||||
|
||||
/// Add an already created primitive to the draw lists.
|
||||
@ -1670,6 +1651,9 @@ impl<'a> SceneBuilder<'a> {
|
||||
} else {
|
||||
self.clip_store.push_clip_root(None, false);
|
||||
}
|
||||
|
||||
// Push this clip id into the hit-testing scene for child primitives
|
||||
self.hit_testing_scene.push_clip(clip_id);
|
||||
}
|
||||
|
||||
// If not redundant, create a stacking context to hold primitive clusters
|
||||
@ -1710,6 +1694,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
// If the stacking context established a clip root, pop off the stack
|
||||
if info.pop_clip_root {
|
||||
self.clip_store.pop_clip_root();
|
||||
self.hit_testing_scene.pop_clip();
|
||||
}
|
||||
|
||||
// If the stacking context was otherwise redundant, early exit
|
||||
@ -2043,7 +2028,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
});
|
||||
|
||||
let instance = SceneClipInstance {
|
||||
key: item.kind,
|
||||
key: item,
|
||||
clip: ClipInstance::new(handle, spatial_node_index),
|
||||
};
|
||||
|
||||
@ -2081,7 +2066,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
});
|
||||
|
||||
let instance = SceneClipInstance {
|
||||
key: item.kind,
|
||||
key: item,
|
||||
clip: ClipInstance::new(handle, spatial_node_index),
|
||||
};
|
||||
|
||||
@ -2123,7 +2108,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
});
|
||||
|
||||
let instance = SceneClipInstance {
|
||||
key: item.kind,
|
||||
key: item,
|
||||
clip: ClipInstance::new(handle, spatial_node_index),
|
||||
};
|
||||
|
||||
@ -2171,7 +2156,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
});
|
||||
instances.push(
|
||||
SceneClipInstance {
|
||||
key: item.kind,
|
||||
key: item,
|
||||
clip: ClipInstance::new(handle, spatial_node_index),
|
||||
},
|
||||
);
|
||||
@ -2197,7 +2182,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
|
||||
instances.push(
|
||||
SceneClipInstance {
|
||||
key: item.kind,
|
||||
key: item,
|
||||
clip: ClipInstance::new(handle, spatial_node_index),
|
||||
},
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user