mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1775369 - Make hit-test API use clip-chains rather than ClipId r=gfx-reviewers,lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D149938
This commit is contained in:
parent
c34e0c3270
commit
fb6ca66ec6
@ -3014,22 +3014,27 @@ pub extern "C" fn wr_dp_push_hit_test(
|
||||
) {
|
||||
debug_assert!(unsafe { !is_in_render_thread() });
|
||||
|
||||
let space_and_clip = parent.to_webrender(state.pipeline_id);
|
||||
|
||||
let clip_rect = clip.intersection(&rect);
|
||||
if clip_rect.is_none() {
|
||||
return;
|
||||
}
|
||||
let tag = (scroll_id, hit_info);
|
||||
|
||||
let prim_info = CommonItemProperties {
|
||||
clip_rect: clip_rect.unwrap(),
|
||||
clip_id: space_and_clip.clip_id,
|
||||
spatial_id: space_and_clip.spatial_id,
|
||||
flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
|
||||
let spatial_id = parent.space.to_webrender(state.pipeline_id);
|
||||
|
||||
let clip_chain_id = if parent.clip_chain == ROOT_CLIP_CHAIN {
|
||||
ClipChainId::INVALID
|
||||
} else {
|
||||
ClipChainId(parent.clip_chain, state.pipeline_id)
|
||||
};
|
||||
|
||||
state.frame_builder.dl_builder.push_hit_test(&prim_info, tag);
|
||||
state.frame_builder.dl_builder.push_hit_test(
|
||||
clip_rect.unwrap(),
|
||||
clip_chain_id,
|
||||
spatial_id,
|
||||
prim_flags(is_backface_visible, false),
|
||||
tag,
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -72,12 +72,24 @@ impl Example for App {
|
||||
// now put some content into it.
|
||||
// start with a white background
|
||||
let info = CommonItemProperties::new((0, 0).to(1000, 1000), space_and_clip1);
|
||||
builder.push_hit_test(&info, (0, 1));
|
||||
builder.push_hit_test(
|
||||
info.clip_rect,
|
||||
ClipChainId::INVALID,
|
||||
info.spatial_id,
|
||||
info.flags,
|
||||
(0, 1)
|
||||
);
|
||||
builder.push_rect(&info, info.clip_rect, ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
|
||||
// let's make a 50x50 blue square as a visual reference
|
||||
let info = CommonItemProperties::new((0, 0).to(50, 50), space_and_clip1);
|
||||
builder.push_hit_test(&info, (0, 2));
|
||||
builder.push_hit_test(
|
||||
info.clip_rect,
|
||||
ClipChainId::INVALID,
|
||||
info.spatial_id,
|
||||
info.flags,
|
||||
(0, 2)
|
||||
);
|
||||
builder.push_rect(&info, info.clip_rect, ColorF::new(0.0, 0.0, 1.0, 1.0));
|
||||
|
||||
// and a 50x50 green square next to it with an offset clip
|
||||
@ -86,7 +98,13 @@ impl Example for App {
|
||||
(50, 0).to(100, 50).intersection(&(60, 10).to(110, 60)).unwrap(),
|
||||
space_and_clip1,
|
||||
);
|
||||
builder.push_hit_test(&info, (0, 3));
|
||||
builder.push_hit_test(
|
||||
info.clip_rect,
|
||||
ClipChainId::INVALID,
|
||||
info.spatial_id,
|
||||
info.flags,
|
||||
(0, 3)
|
||||
);
|
||||
builder.push_rect(&info, info.clip_rect, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
|
||||
// Below the above rectangles, set up a nested scrollbox. It's still in
|
||||
@ -113,13 +131,25 @@ impl Example for App {
|
||||
(-1000, -1000).to(5000, 5000),
|
||||
space_and_clip2,
|
||||
);
|
||||
builder.push_hit_test(&info, (0, 4));
|
||||
builder.push_hit_test(
|
||||
info.clip_rect,
|
||||
ClipChainId::INVALID,
|
||||
info.spatial_id,
|
||||
info.flags,
|
||||
(0, 4)
|
||||
);
|
||||
builder.push_rect(&info, info.clip_rect, ColorF::new(0.5, 0.5, 0.5, 1.0));
|
||||
|
||||
// add a teal square to visualize the scrolling/clipping behaviour
|
||||
// as you scroll the nested scrollbox
|
||||
let info = CommonItemProperties::new((0, 200).to(50, 250), space_and_clip2);
|
||||
builder.push_hit_test(&info, (0, 5));
|
||||
builder.push_hit_test(
|
||||
info.clip_rect,
|
||||
ClipChainId::INVALID,
|
||||
info.spatial_id,
|
||||
info.flags,
|
||||
(0, 5)
|
||||
);
|
||||
builder.push_rect(&info, info.clip_rect, ColorF::new(0.0, 1.0, 1.0, 1.0));
|
||||
|
||||
// Add a sticky frame. It will "stick" twice while scrolling, once
|
||||
@ -143,7 +173,13 @@ impl Example for App {
|
||||
clip_id: space_and_clip2.clip_id,
|
||||
},
|
||||
);
|
||||
builder.push_hit_test(&info, (0, 6));
|
||||
builder.push_hit_test(
|
||||
info.clip_rect,
|
||||
ClipChainId::INVALID,
|
||||
info.spatial_id,
|
||||
info.flags,
|
||||
(0, 6)
|
||||
);
|
||||
builder.push_rect(
|
||||
&info,
|
||||
info.clip_rect,
|
||||
@ -156,7 +192,13 @@ impl Example for App {
|
||||
(250, 350).to(300, 400),
|
||||
space_and_clip2,
|
||||
);
|
||||
builder.push_hit_test(&info, (0, 7));
|
||||
builder.push_hit_test(
|
||||
info.clip_rect,
|
||||
ClipChainId::INVALID,
|
||||
info.spatial_id,
|
||||
info.flags,
|
||||
(0, 7)
|
||||
);
|
||||
builder.push_rect(&info, info.clip_rect, ColorF::new(0.0, 1.0, 1.0, 1.0));
|
||||
|
||||
builder.pop_stacking_context();
|
||||
|
@ -762,6 +762,13 @@ impl<'a> SceneBuilder<'a> {
|
||||
kind: ContextKind<'a>,
|
||||
}
|
||||
|
||||
let invalid_clip_chain_id = ClipId::ClipChain(api::ClipChainId::INVALID);
|
||||
self.clip_store.register_clip_template(
|
||||
invalid_clip_chain_id,
|
||||
invalid_clip_chain_id,
|
||||
&[],
|
||||
);
|
||||
|
||||
let root_clip_id = ClipId::root(root_pipeline.pipeline_id);
|
||||
self.clip_store.register_clip_template(root_clip_id, root_clip_id, &[]);
|
||||
self.clip_store.push_clip_root(Some(root_clip_id), false);
|
||||
@ -1356,20 +1363,28 @@ impl<'a> SceneBuilder<'a> {
|
||||
DisplayItem::HitTest(ref info) => {
|
||||
profile_scope!("hit_test");
|
||||
|
||||
// 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,
|
||||
let spatial_node_index = self.get_space(info.spatial_id);
|
||||
let current_offset = self.current_offset(spatial_node_index);
|
||||
let unsnapped_rect = info.rect.translate(current_offset);
|
||||
|
||||
let rect = self.snap_rect(
|
||||
&unsnapped_rect,
|
||||
spatial_node_index,
|
||||
);
|
||||
|
||||
// Don't add transparent rectangles to the draw list,
|
||||
// but do consider them for hit testing. This allows
|
||||
// specifying invisible hit testing areas.
|
||||
let layout = LayoutPrimitiveInfo {
|
||||
rect,
|
||||
clip_rect: rect,
|
||||
flags: info.flags,
|
||||
};
|
||||
|
||||
// TODO(gw): Port internal API to be ClipChain based, rather than ClipId once all callers updated
|
||||
let clip_id = ClipId::ClipChain(info.clip_chain_id);
|
||||
|
||||
self.add_primitive_to_hit_testing_list(
|
||||
&layout,
|
||||
spatial_node_index,
|
||||
info.common.clip_id,
|
||||
clip_id,
|
||||
info.tag,
|
||||
);
|
||||
}
|
||||
|
@ -365,7 +365,10 @@ pub struct ClearRectangleDisplayItem {
|
||||
/// distinct item also makes it easier to inspect/debug display items.
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct HitTestDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
pub rect: LayoutRect,
|
||||
pub clip_chain_id: ClipChainId,
|
||||
pub spatial_id: SpatialId,
|
||||
pub flags: PrimitiveFlags,
|
||||
pub tag: ItemTag,
|
||||
}
|
||||
|
||||
@ -1633,6 +1636,10 @@ impl From<FillRule> for u8 {
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ClipChainId(pub u64, pub PipelineId);
|
||||
|
||||
impl ClipChainId {
|
||||
pub const INVALID: Self = ClipChainId(!0, PipelineId::INVALID);
|
||||
}
|
||||
|
||||
/// A reference to a clipping node defining how an item is clipped.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ClipId {
|
||||
|
@ -1350,11 +1350,17 @@ impl DisplayListBuilder {
|
||||
|
||||
pub fn push_hit_test(
|
||||
&mut self,
|
||||
common: &di::CommonItemProperties,
|
||||
rect: LayoutRect,
|
||||
clip_chain_id: di::ClipChainId,
|
||||
spatial_id: di::SpatialId,
|
||||
flags: di::PrimitiveFlags,
|
||||
tag: di::ItemTag,
|
||||
) {
|
||||
let item = di::DisplayItem::HitTest(di::HitTestDisplayItem {
|
||||
common: *common,
|
||||
rect,
|
||||
clip_chain_id,
|
||||
spatial_id,
|
||||
flags,
|
||||
tag,
|
||||
});
|
||||
self.push_item(&item);
|
||||
|
@ -159,6 +159,8 @@ impl PipelineId {
|
||||
pub fn dummy() -> Self {
|
||||
PipelineId(!0, !0)
|
||||
}
|
||||
|
||||
pub const INVALID: Self = PipelineId(!0, !0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1331,24 +1331,27 @@ impl<'a> RawtestHarness<'a> {
|
||||
builder.begin();
|
||||
|
||||
// Add a rectangle that covers the entire scene.
|
||||
let info = self.make_common_properties(LayoutRect::from_size(layout_size));
|
||||
let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id);
|
||||
builder.push_hit_test(
|
||||
&info,
|
||||
LayoutRect::from_size(layout_size),
|
||||
ClipChainId::INVALID,
|
||||
space_and_clip.spatial_id,
|
||||
PrimitiveFlags::default(),
|
||||
(0, 1),
|
||||
);
|
||||
|
||||
// Add a simple 100x100 rectangle at 100,0.
|
||||
let info = self.make_common_properties(LayoutRect::from_origin_and_size(
|
||||
LayoutPoint::new(100., 0.),
|
||||
LayoutSize::new(100., 100.)
|
||||
));
|
||||
builder.push_hit_test(
|
||||
&info,
|
||||
LayoutRect::from_origin_and_size(
|
||||
LayoutPoint::new(100., 0.),
|
||||
LayoutSize::new(100., 100.)
|
||||
),
|
||||
ClipChainId::INVALID,
|
||||
space_and_clip.spatial_id,
|
||||
PrimitiveFlags::default(),
|
||||
(0, 2),
|
||||
);
|
||||
|
||||
let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id);
|
||||
|
||||
let make_rounded_complex_clip = |rect: &LayoutRect, radius: f32| -> ComplexClipRegion {
|
||||
ComplexClipRegion::new(
|
||||
*rect,
|
||||
@ -1363,13 +1366,12 @@ impl<'a> RawtestHarness<'a> {
|
||||
&space_and_clip,
|
||||
make_rounded_complex_clip(&rect, 20.),
|
||||
);
|
||||
let clip_chain_id = builder.define_clip_chain(None, vec![temp_clip_id]);
|
||||
builder.push_hit_test(
|
||||
&CommonItemProperties {
|
||||
clip_rect: rect,
|
||||
clip_id: temp_clip_id,
|
||||
spatial_id: space_and_clip.spatial_id,
|
||||
flags: PrimitiveFlags::default(),
|
||||
},
|
||||
rect,
|
||||
clip_chain_id,
|
||||
space_and_clip.spatial_id,
|
||||
PrimitiveFlags::default(),
|
||||
(0, 4),
|
||||
);
|
||||
|
||||
@ -1381,12 +1383,10 @@ impl<'a> RawtestHarness<'a> {
|
||||
);
|
||||
let clip_chain_id = builder.define_clip_chain(None, vec![clip_id]);
|
||||
builder.push_hit_test(
|
||||
&CommonItemProperties {
|
||||
clip_rect: rect,
|
||||
clip_id: ClipId::ClipChain(clip_chain_id),
|
||||
spatial_id: space_and_clip.spatial_id,
|
||||
flags: PrimitiveFlags::default(),
|
||||
},
|
||||
rect,
|
||||
clip_chain_id,
|
||||
space_and_clip.spatial_id,
|
||||
PrimitiveFlags::default(),
|
||||
(0, 5),
|
||||
);
|
||||
|
||||
|
@ -878,9 +878,17 @@ impl YamlFrameReader {
|
||||
&info.clip_rect
|
||||
);
|
||||
|
||||
let clip_chain_id = match info.clip_id {
|
||||
ClipId::Clip(..) => panic!("bug: must be a clip-chain"),
|
||||
ClipId::ClipChain(id) => id,
|
||||
};
|
||||
|
||||
if let Some(tag) = self.to_hit_testing_tag(&item["hit-testing-tag"]) {
|
||||
dl.push_hit_test(
|
||||
info,
|
||||
info.clip_rect,
|
||||
clip_chain_id,
|
||||
info.spatial_id,
|
||||
info.flags,
|
||||
tag,
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user