Skip to content

Commit 25827f5

Browse files
mrobinsonmukilan
authored andcommitted
Restore some hit testing APIs
These APIs are still used by Servo, so keep them around until Servo can migrate off of them.
1 parent d5ce6cf commit 25827f5

File tree

6 files changed

+82
-14
lines changed

6 files changed

+82
-14
lines changed

webrender/src/hit_test.rs

+55-6
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
use api::{BorderRadius, ClipMode, HitTestResultItem, HitTestResult, ItemTag, PrimitiveFlags};
6-
use api::{PipelineId, ApiHitTester};
5+
use api::{BorderRadius, ClipMode, HitTestFlags, HitTestResultItem, HitTestResult, ItemTag, PrimitiveFlags};
6+
use api::{ApiHitTester, PipelineId};
77
use api::units::*;
88
use crate::clip::{rounded_rectangle_contains_point, ClipNodeId, ClipTreeBuilder};
99
use crate::clip::{polygon_contains_point, ClipItemKey, ClipItemKeyKind};
@@ -41,10 +41,13 @@ impl SharedHitTester {
4141
}
4242

4343
impl ApiHitTester for SharedHitTester {
44-
fn hit_test(&self,
44+
fn hit_test(
45+
&self,
46+
pipeline_id: Option<PipelineId>,
4547
point: WorldPoint,
48+
flags: HitTestFlags,
4649
) -> HitTestResult {
47-
self.get_ref().hit_test(HitTest::new(point))
50+
self.get_ref().hit_test(HitTest::new(pipeline_id, point, flags))
4851
}
4952
}
5053

@@ -280,13 +283,15 @@ pub struct HitTester {
280283
#[ignore_malloc_size_of = "Arc"]
281284
scene: Arc<HitTestingScene>,
282285
spatial_nodes: FastHashMap<SpatialNodeIndex, HitTestSpatialNode>,
286+
pipeline_root_nodes: FastHashMap<PipelineId, SpatialNodeIndex>,
283287
}
284288

285289
impl HitTester {
286290
pub fn empty() -> Self {
287291
HitTester {
288292
scene: Arc::new(HitTestingScene::new(&HitTestingSceneStats::empty())),
289293
spatial_nodes: FastHashMap::default(),
294+
pipeline_root_nodes: FastHashMap::default(),
290295
}
291296
}
292297

@@ -297,6 +302,7 @@ impl HitTester {
297302
let mut hit_tester = HitTester {
298303
scene,
299304
spatial_nodes: FastHashMap::default(),
305+
pipeline_root_nodes: FastHashMap::default(),
300306
};
301307
hit_tester.read_spatial_tree(spatial_tree);
302308
hit_tester
@@ -309,7 +315,13 @@ impl HitTester {
309315
self.spatial_nodes.clear();
310316
self.spatial_nodes.reserve(spatial_tree.spatial_node_count());
311317

318+
self.pipeline_root_nodes.clear();
319+
312320
spatial_tree.visit_nodes(|index, node| {
321+
// If we haven't already seen a node for this pipeline, record this one as the root
322+
// node.
323+
self.pipeline_root_nodes.entry(node.pipeline_id).or_insert(index);
324+
313325
//TODO: avoid inverting more than necessary:
314326
// - if the coordinate system is non-invertible, no need to try any of these concrete transforms
315327
// - if there are other places where inversion is needed, let's not repeat the step
@@ -328,6 +340,8 @@ impl HitTester {
328340
}
329341

330342
pub fn hit_test(&self, test: HitTest) -> HitTestResult {
343+
let point = test.get_absolute_point(self);
344+
331345
let mut result = HitTestResult::default();
332346

333347
let mut current_spatial_node_index = SpatialNodeIndex::INVALID;
@@ -344,7 +358,7 @@ impl HitTester {
344358
point_in_layer = scroll_node
345359
.world_content_transform
346360
.inverse()
347-
.and_then(|inverted| inverted.project_point2d(test.point));
361+
.and_then(|inverted| inverted.project_point2d(point));
348362
current_spatial_node_index = item.spatial_node_index;
349363
}
350364

@@ -372,7 +386,7 @@ impl HitTester {
372386
.world_content_transform;
373387
if let Some(transformed_point) = transform
374388
.inverse()
375-
.and_then(|inverted| inverted.project_point2d(test.point))
389+
.and_then(|inverted| inverted.project_point2d(point))
376390
{
377391
if !clip_node.region.contains(&transformed_point) {
378392
is_valid = false;
@@ -397,24 +411,59 @@ impl HitTester {
397411
tag: item.tag,
398412
animation_id: item.animation_id,
399413
});
414+
415+
if !test.flags.contains(HitTestFlags::FIND_ALL) {
416+
return result;
417+
}
400418
}
401419

402420
result.items.dedup();
403421
result
404422
}
423+
424+
fn get_pipeline_root(&self, pipeline_id: PipelineId) -> &HitTestSpatialNode {
425+
&self.spatial_nodes[&self.pipeline_root_nodes[&pipeline_id]]
426+
}
427+
405428
}
406429

407430
#[derive(MallocSizeOf)]
408431
pub struct HitTest {
432+
pipeline_id: Option<PipelineId>,
409433
point: WorldPoint,
434+
#[ignore_malloc_size_of = "bitflags"]
435+
flags: HitTestFlags,
410436
}
411437

412438
impl HitTest {
413439
pub fn new(
440+
pipeline_id: Option<PipelineId>,
414441
point: WorldPoint,
442+
flags: HitTestFlags,
415443
) -> HitTest {
416444
HitTest {
445+
pipeline_id,
417446
point,
447+
flags
448+
}
449+
}
450+
451+
fn get_absolute_point(&self, hit_tester: &HitTester) -> WorldPoint {
452+
if !self.flags.contains(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT) {
453+
return self.point;
418454
}
455+
456+
let point = LayoutPoint::new(self.point.x, self.point.y);
457+
self.pipeline_id
458+
.and_then(|id|
459+
hit_tester
460+
.get_pipeline_root(id)
461+
.world_viewport_transform
462+
.transform_point2d(point)
463+
)
464+
.unwrap_or_else(|| {
465+
WorldPoint::new(self.point.x, self.point.y)
466+
})
419467
}
468+
420469
}

webrender/src/render_api.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::marker::PhantomData;
1010
use std::path::PathBuf;
1111
use std::sync::Arc;
1212
use std::u32;
13-
use api::MinimapData;
13+
use api::{HitTestFlags, MinimapData};
1414
use time::precise_time_ns;
1515
use crate::api::channel::{Sender, single_msg_channel, unbounded_channel};
1616
use crate::api::{BuiltDisplayList, IdNamespace, ExternalScrollId, Parameter, BoolParameter};
@@ -792,7 +792,7 @@ pub enum FrameMsg {
792792
///
793793
UpdateEpoch(PipelineId, Epoch),
794794
///
795-
HitTest(WorldPoint, Sender<HitTestResult>),
795+
HitTest(Option<PipelineId>, WorldPoint, HitTestFlags, Sender<HitTestResult>),
796796
///
797797
RequestHitTester(Sender<Arc<dyn ApiHitTester>>),
798798
///
@@ -1276,13 +1276,15 @@ impl RenderApi {
12761276
/// front to back.
12771277
pub fn hit_test(&self,
12781278
document_id: DocumentId,
1279+
pipeline_id: Option<PipelineId>,
12791280
point: WorldPoint,
1281+
flags: HitTestFlags,
12801282
) -> HitTestResult {
12811283
let (tx, rx) = single_msg_channel();
12821284

12831285
self.send_frame_msg(
12841286
document_id,
1285-
FrameMsg::HitTest(point, tx)
1287+
FrameMsg::HitTest(pipeline_id, point, flags, tx)
12861288
);
12871289
rx.recv().unwrap()
12881290
}

webrender/src/render_backend.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -443,14 +443,14 @@ impl Document {
443443
FrameMsg::UpdateEpoch(pipeline_id, epoch) => {
444444
self.scene.pipeline_epochs.insert(pipeline_id, epoch);
445445
}
446-
FrameMsg::HitTest(point, tx) => {
446+
FrameMsg::HitTest(pipeline_id, point, flags, tx) => {
447447
if !self.hit_tester_is_valid {
448448
self.rebuild_hit_tester();
449449
}
450450

451451
let result = match self.hit_tester {
452452
Some(ref hit_tester) => {
453-
hit_tester.hit_test(HitTest::new(point))
453+
hit_tester.hit_test(HitTest::new(pipeline_id, point, flags))
454454
}
455455
None => HitTestResult { items: Vec::new() },
456456
};

webrender_api/src/lib.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,11 @@ impl NotificationRequest {
336336
/// the RenderBackendThread.
337337
pub trait ApiHitTester: Send + Sync {
338338
/// Does a hit test on display items in the specified document, at the given
339-
/// point. The vector of hit results will contain all display items that match,
340-
/// ordered from front to back.
341-
fn hit_test(&self, point: WorldPoint) -> HitTestResult;
339+
/// point. If a pipeline_id is specified, it is used to further restrict the
340+
/// hit results so that only items inside that pipeline are matched. The vector
341+
/// of hit results will contain all display items that match, ordered from
342+
/// front to back.
343+
fn hit_test(&self, pipeline_id: Option<PipelineId>, point: WorldPoint, flags: HitTestFlags) -> HitTestResult;
342344
}
343345

344346
/// A hit tester requested to the render backend thread but not necessarily ready yet.
@@ -376,6 +378,17 @@ pub struct HitTestResult {
376378
pub items: Vec<HitTestResultItem>,
377379
}
378380

381+
bitflags! {
382+
#[derive(Deserialize, Serialize)]
383+
///
384+
pub struct HitTestFlags: u8 {
385+
///
386+
const FIND_ALL = 0b00000001;
387+
///
388+
const POINT_RELATIVE_TO_PIPELINE_VIEWPORT = 0b00000010;
389+
}
390+
}
391+
379392
impl Drop for NotificationRequest {
380393
fn drop(&mut self) {
381394
if let Some(ref mut handler) = self.handler {

wrench/src/main.rs

+2
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,9 @@ fn render<'a>(
984984
VirtualKeyCode::X => {
985985
let results = wrench.api.hit_test(
986986
wrench.document_id,
987+
None,
987988
cursor_position,
989+
HitTestFlags::empty(),
988990
);
989991

990992
println!("Hit test results:");

wrench/src/rawtest.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1387,7 +1387,9 @@ impl<'a> RawtestHarness<'a> {
13871387
let hit_test = |point: WorldPoint| -> HitTestResult {
13881388
self.wrench.api.hit_test(
13891389
self.wrench.document_id,
1390+
None,
13901391
point,
1392+
HitTestFlags::empty(),
13911393
)
13921394
};
13931395

0 commit comments

Comments
 (0)