2
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
4
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 } ;
7
7
use api:: units:: * ;
8
8
use crate :: clip:: { rounded_rectangle_contains_point, ClipNodeId , ClipTreeBuilder } ;
9
9
use crate :: clip:: { polygon_contains_point, ClipItemKey , ClipItemKeyKind } ;
@@ -41,10 +41,13 @@ impl SharedHitTester {
41
41
}
42
42
43
43
impl ApiHitTester for SharedHitTester {
44
- fn hit_test ( & self ,
44
+ fn hit_test (
45
+ & self ,
46
+ pipeline_id : Option < PipelineId > ,
45
47
point : WorldPoint ,
48
+ flags : HitTestFlags ,
46
49
) -> HitTestResult {
47
- self . get_ref ( ) . hit_test ( HitTest :: new ( point) )
50
+ self . get_ref ( ) . hit_test ( HitTest :: new ( pipeline_id , point, flags ) )
48
51
}
49
52
}
50
53
@@ -280,13 +283,15 @@ pub struct HitTester {
280
283
#[ ignore_malloc_size_of = "Arc" ]
281
284
scene : Arc < HitTestingScene > ,
282
285
spatial_nodes : FastHashMap < SpatialNodeIndex , HitTestSpatialNode > ,
286
+ pipeline_root_nodes : FastHashMap < PipelineId , SpatialNodeIndex > ,
283
287
}
284
288
285
289
impl HitTester {
286
290
pub fn empty ( ) -> Self {
287
291
HitTester {
288
292
scene : Arc :: new ( HitTestingScene :: new ( & HitTestingSceneStats :: empty ( ) ) ) ,
289
293
spatial_nodes : FastHashMap :: default ( ) ,
294
+ pipeline_root_nodes : FastHashMap :: default ( ) ,
290
295
}
291
296
}
292
297
@@ -297,6 +302,7 @@ impl HitTester {
297
302
let mut hit_tester = HitTester {
298
303
scene,
299
304
spatial_nodes : FastHashMap :: default ( ) ,
305
+ pipeline_root_nodes : FastHashMap :: default ( ) ,
300
306
} ;
301
307
hit_tester. read_spatial_tree ( spatial_tree) ;
302
308
hit_tester
@@ -309,7 +315,13 @@ impl HitTester {
309
315
self . spatial_nodes . clear ( ) ;
310
316
self . spatial_nodes . reserve ( spatial_tree. spatial_node_count ( ) ) ;
311
317
318
+ self . pipeline_root_nodes . clear ( ) ;
319
+
312
320
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
+
313
325
//TODO: avoid inverting more than necessary:
314
326
// - if the coordinate system is non-invertible, no need to try any of these concrete transforms
315
327
// - if there are other places where inversion is needed, let's not repeat the step
@@ -328,6 +340,8 @@ impl HitTester {
328
340
}
329
341
330
342
pub fn hit_test ( & self , test : HitTest ) -> HitTestResult {
343
+ let point = test. get_absolute_point ( self ) ;
344
+
331
345
let mut result = HitTestResult :: default ( ) ;
332
346
333
347
let mut current_spatial_node_index = SpatialNodeIndex :: INVALID ;
@@ -344,7 +358,7 @@ impl HitTester {
344
358
point_in_layer = scroll_node
345
359
. world_content_transform
346
360
. inverse ( )
347
- . and_then ( |inverted| inverted. project_point2d ( test . point ) ) ;
361
+ . and_then ( |inverted| inverted. project_point2d ( point) ) ;
348
362
current_spatial_node_index = item. spatial_node_index ;
349
363
}
350
364
@@ -372,7 +386,7 @@ impl HitTester {
372
386
. world_content_transform ;
373
387
if let Some ( transformed_point) = transform
374
388
. inverse ( )
375
- . and_then ( |inverted| inverted. project_point2d ( test . point ) )
389
+ . and_then ( |inverted| inverted. project_point2d ( point) )
376
390
{
377
391
if !clip_node. region . contains ( & transformed_point) {
378
392
is_valid = false ;
@@ -397,24 +411,59 @@ impl HitTester {
397
411
tag : item. tag ,
398
412
animation_id : item. animation_id ,
399
413
} ) ;
414
+
415
+ if !test. flags . contains ( HitTestFlags :: FIND_ALL ) {
416
+ return result;
417
+ }
400
418
}
401
419
402
420
result. items . dedup ( ) ;
403
421
result
404
422
}
423
+
424
+ fn get_pipeline_root ( & self , pipeline_id : PipelineId ) -> & HitTestSpatialNode {
425
+ & self . spatial_nodes [ & self . pipeline_root_nodes [ & pipeline_id] ]
426
+ }
427
+
405
428
}
406
429
407
430
#[ derive( MallocSizeOf ) ]
408
431
pub struct HitTest {
432
+ pipeline_id : Option < PipelineId > ,
409
433
point : WorldPoint ,
434
+ #[ ignore_malloc_size_of = "bitflags" ]
435
+ flags : HitTestFlags ,
410
436
}
411
437
412
438
impl HitTest {
413
439
pub fn new (
440
+ pipeline_id : Option < PipelineId > ,
414
441
point : WorldPoint ,
442
+ flags : HitTestFlags ,
415
443
) -> HitTest {
416
444
HitTest {
445
+ pipeline_id,
417
446
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 ;
418
454
}
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
+ } )
419
467
}
468
+
420
469
}
0 commit comments