@@ -59,6 +59,12 @@ pub fn common_filter(node: &Node) -> FilterResult {
59
59
60
60
if let Some ( parent) = node. filtered_parent ( & common_filter_without_parent_checks) {
61
61
if parent. clips_children ( ) {
62
+ // If the parent clips its children, then exclude this subtree
63
+ // if this child's bounding box isn't inside the parent's bounding
64
+ // box, and if the previous or next filtered sibling isn't inside
65
+ // the parent's bounding box either. The latter condition is meant
66
+ // to allow off-screen items to be seen by consumers so they can be
67
+ // scrolled into view.
62
68
if let Some ( bbox) = node. bounding_box ( ) {
63
69
if let Some ( parent_bbox) = parent. bounding_box ( ) {
64
70
if bbox. intersect ( parent_bbox) . is_empty ( )
@@ -89,7 +95,7 @@ pub fn common_filter_with_root_exception(node: &Node) -> FilterResult {
89
95
90
96
#[ cfg( test) ]
91
97
mod tests {
92
- use accesskit:: { Node , NodeId , Role , Tree , TreeUpdate } ;
98
+ use accesskit:: { Node , NodeId , Rect , Role , Tree , TreeUpdate } ;
93
99
use alloc:: vec;
94
100
95
101
use super :: { common_filter, common_filter_with_root_exception, FilterResult } ;
@@ -266,4 +272,133 @@ mod tests {
266
272
common_filter( & tree. state( ) . node_by_id( NodeId ( 1 ) ) . unwrap( ) )
267
273
) ;
268
274
}
275
+
276
+ #[ test]
277
+ fn clipped_children ( ) {
278
+ let update = TreeUpdate {
279
+ nodes : vec ! [
280
+ ( NodeId ( 0 ) , {
281
+ let mut node = Node :: new( Role :: ScrollView ) ;
282
+ node. set_clips_children( ) ;
283
+ node. set_bounds( Rect :: new( 0.0 , 0.0 , 30.0 , 30.0 ) ) ;
284
+ node. set_children( vec![
285
+ NodeId ( 1 ) ,
286
+ NodeId ( 2 ) ,
287
+ NodeId ( 3 ) ,
288
+ NodeId ( 4 ) ,
289
+ NodeId ( 5 ) ,
290
+ NodeId ( 6 ) ,
291
+ NodeId ( 7 ) ,
292
+ NodeId ( 8 ) ,
293
+ NodeId ( 9 ) ,
294
+ NodeId ( 10 ) ,
295
+ NodeId ( 11 ) ,
296
+ ] ) ;
297
+ node
298
+ } ) ,
299
+ ( NodeId ( 1 ) , {
300
+ let mut node = Node :: new( Role :: Unknown ) ;
301
+ node. set_bounds( Rect :: new( 0.0 , -30.0 , 30.0 , -20.0 ) ) ;
302
+ node
303
+ } ) ,
304
+ ( NodeId ( 2 ) , {
305
+ let mut node = Node :: new( Role :: Unknown ) ;
306
+ node. set_bounds( Rect :: new( 0.0 , -20.0 , 30.0 , -10.0 ) ) ;
307
+ node
308
+ } ) ,
309
+ ( NodeId ( 3 ) , {
310
+ let mut node = Node :: new( Role :: Unknown ) ;
311
+ node. set_bounds( Rect :: new( 0.0 , -10.0 , 30.0 , 0.0 ) ) ;
312
+ node
313
+ } ) ,
314
+ ( NodeId ( 4 ) , {
315
+ let mut node = Node :: new( Role :: Unknown ) ;
316
+ node. set_hidden( ) ;
317
+ node
318
+ } ) ,
319
+ ( NodeId ( 5 ) , {
320
+ let mut node = Node :: new( Role :: Unknown ) ;
321
+ node. set_bounds( Rect :: new( 0.0 , 0.0 , 30.0 , 10.0 ) ) ;
322
+ node
323
+ } ) ,
324
+ ( NodeId ( 6 ) , {
325
+ let mut node = Node :: new( Role :: Unknown ) ;
326
+ node. set_bounds( Rect :: new( 0.0 , 10.0 , 30.0 , 20.0 ) ) ;
327
+ node
328
+ } ) ,
329
+ ( NodeId ( 7 ) , {
330
+ let mut node = Node :: new( Role :: Unknown ) ;
331
+ node. set_bounds( Rect :: new( 0.0 , 20.0 , 30.0 , 30.0 ) ) ;
332
+ node
333
+ } ) ,
334
+ ( NodeId ( 8 ) , {
335
+ let mut node = Node :: new( Role :: Unknown ) ;
336
+ node. set_hidden( ) ;
337
+ node
338
+ } ) ,
339
+ ( NodeId ( 9 ) , {
340
+ let mut node = Node :: new( Role :: Unknown ) ;
341
+ node. set_bounds( Rect :: new( 0.0 , 30.0 , 30.0 , 40.0 ) ) ;
342
+ node
343
+ } ) ,
344
+ ( NodeId ( 10 ) , {
345
+ let mut node = Node :: new( Role :: Unknown ) ;
346
+ node. set_bounds( Rect :: new( 0.0 , 40.0 , 30.0 , 50.0 ) ) ;
347
+ node
348
+ } ) ,
349
+ ( NodeId ( 11 ) , {
350
+ let mut node = Node :: new( Role :: Unknown ) ;
351
+ node. set_bounds( Rect :: new( 0.0 , 50.0 , 30.0 , 60.0 ) ) ;
352
+ node
353
+ } ) ,
354
+ ] ,
355
+ tree : Some ( Tree :: new ( NodeId ( 0 ) ) ) ,
356
+ focus : NodeId ( 0 ) ,
357
+ } ;
358
+ let tree = crate :: Tree :: new ( update, false ) ;
359
+ assert_eq ! (
360
+ FilterResult :: ExcludeSubtree ,
361
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 1 ) ) . unwrap( ) )
362
+ ) ;
363
+ assert_eq ! (
364
+ FilterResult :: ExcludeSubtree ,
365
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 2 ) ) . unwrap( ) )
366
+ ) ;
367
+ assert_eq ! (
368
+ FilterResult :: Include ,
369
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 3 ) ) . unwrap( ) )
370
+ ) ;
371
+ assert_eq ! (
372
+ FilterResult :: ExcludeSubtree ,
373
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 4 ) ) . unwrap( ) )
374
+ ) ;
375
+ assert_eq ! (
376
+ FilterResult :: Include ,
377
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 5 ) ) . unwrap( ) )
378
+ ) ;
379
+ assert_eq ! (
380
+ FilterResult :: Include ,
381
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 6 ) ) . unwrap( ) )
382
+ ) ;
383
+ assert_eq ! (
384
+ FilterResult :: Include ,
385
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 7 ) ) . unwrap( ) )
386
+ ) ;
387
+ assert_eq ! (
388
+ FilterResult :: ExcludeSubtree ,
389
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 8 ) ) . unwrap( ) )
390
+ ) ;
391
+ assert_eq ! (
392
+ FilterResult :: Include ,
393
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 9 ) ) . unwrap( ) )
394
+ ) ;
395
+ assert_eq ! (
396
+ FilterResult :: ExcludeSubtree ,
397
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 10 ) ) . unwrap( ) )
398
+ ) ;
399
+ assert_eq ! (
400
+ FilterResult :: ExcludeSubtree ,
401
+ common_filter( & tree. state( ) . node_by_id( NodeId ( 11 ) ) . unwrap( ) )
402
+ ) ;
403
+ }
269
404
}
0 commit comments