@@ -14,6 +14,7 @@ use accesskit::{
1414} ;
1515use alloc:: {
1616 string:: { String , ToString } ,
17+ vec,
1718 vec:: Vec ,
1819} ;
1920use core:: { fmt, iter:: FusedIterator } ;
@@ -121,13 +122,13 @@ impl<'a> Node<'a> {
121122 }
122123
123124 pub fn filtered_parent ( & self , filter : & impl Fn ( & Node ) -> FilterResult ) -> Option < Node < ' a > > {
124- self . parent ( ) . and_then ( move |parent| {
125- if filter ( & parent) == FilterResult :: Include {
126- Some ( parent)
127- } else {
128- parent. filtered_parent ( filter)
125+ let mut current = self . parent ( ) ?;
126+ loop {
127+ if filter ( & current) == FilterResult :: Include {
128+ return Some ( current) ;
129129 }
130- } )
130+ current = current. parent ( ) ?;
131+ }
131132 }
132133
133134 pub fn parent_and_index ( self ) -> Option < ( Node < ' a > , usize ) > {
@@ -283,13 +284,16 @@ impl<'a> Node<'a> {
283284 }
284285
285286 pub fn is_descendant_of ( & self , ancestor : & Node ) -> bool {
286- if self . id ( ) == ancestor. id ( ) {
287- return true ;
288- }
289- if let Some ( parent) = self . parent ( ) {
290- return parent. is_descendant_of ( ancestor) ;
287+ let mut current = * self ;
288+ loop {
289+ if current. id ( ) == ancestor. id ( ) {
290+ return true ;
291+ }
292+ match current. parent ( ) {
293+ Some ( parent) => current = parent,
294+ None => return false ,
295+ }
291296 }
292- false
293297 }
294298
295299 /// Returns the transform defined directly on this node, or the identity
@@ -303,22 +307,26 @@ impl<'a> Node<'a> {
303307 /// Returns the combined affine transform of this node and its ancestors,
304308 /// up to and including the root of this node's tree.
305309 pub fn transform ( & self ) -> Affine {
306- self . parent ( )
307- . map_or ( Affine :: IDENTITY , |parent| parent. transform ( ) )
308- * self . direct_transform ( )
310+ let mut acc = self . direct_transform ( ) ;
311+ let mut current = * self ;
312+ while let Some ( parent) = current. parent ( ) {
313+ acc = parent. direct_transform ( ) * acc;
314+ current = parent;
315+ }
316+ acc
309317 }
310318
311319 pub ( crate ) fn relative_transform ( & self , stop_at : & Node ) -> Affine {
312- let parent_transform = if let Some ( parent) = self . parent ( ) {
320+ let mut acc = self . direct_transform ( ) ;
321+ let mut current = * self ;
322+ while let Some ( parent) = current. parent ( ) {
313323 if parent. id ( ) == stop_at. id ( ) {
314- Affine :: IDENTITY
315- } else {
316- parent. relative_transform ( stop_at)
324+ break ;
317325 }
318- } else {
319- Affine :: IDENTITY
320- } ;
321- parent_transform * self . direct_transform ( )
326+ acc = parent . direct_transform ( ) * acc ;
327+ current = parent ;
328+ }
329+ acc
322330 }
323331
324332 pub fn raw_bounds ( & self ) -> Option < Rect > {
@@ -348,23 +356,37 @@ impl<'a> Node<'a> {
348356 point : Point ,
349357 filter : & impl Fn ( & Node ) -> FilterResult ,
350358 ) -> Option < ( Node < ' a > , Point ) > {
351- let filter_result = filter ( self ) ;
352-
353- if filter_result == FilterResult :: ExcludeSubtree {
354- return None ;
359+ // A node's `Test` frame is pushed before its children, then children in
360+ // forward order, so that children are searched last-to-first and the
361+ // node's own bounds are tested only after all descendants miss.
362+ enum Frame < ' n > {
363+ Visit ( Node < ' n > , Point ) ,
364+ Test ( Node < ' n > , Point ) ,
355365 }
356366
357- for child in self . children ( ) . rev ( ) {
358- let point = child. direct_transform ( ) . inverse ( ) * point;
359- if let Some ( result) = child. hit_test ( point, filter) {
360- return Some ( result) ;
361- }
362- }
363-
364- if filter_result == FilterResult :: Include {
365- if let Some ( rect) = & self . raw_bounds ( ) {
366- if rect. contains ( point) {
367- return Some ( ( * self , point) ) ;
367+ let mut stack = Vec :: with_capacity ( self . children ( ) . len ( ) + 1 ) ;
368+ stack. push ( Frame :: Visit ( * self , point) ) ;
369+ while let Some ( frame) = stack. pop ( ) {
370+ match frame {
371+ Frame :: Test ( node, point) => {
372+ if let Some ( rect) = & node. raw_bounds ( ) {
373+ if rect. contains ( point) {
374+ return Some ( ( node, point) ) ;
375+ }
376+ }
377+ }
378+ Frame :: Visit ( node, point) => {
379+ let filter_result = filter ( & node) ;
380+ if filter_result == FilterResult :: ExcludeSubtree {
381+ continue ;
382+ }
383+ if filter_result == FilterResult :: Include {
384+ stack. push ( Frame :: Test ( node, point) ) ;
385+ }
386+ for child in node. children ( ) {
387+ let child_point = child. direct_transform ( ) . inverse ( ) * point;
388+ stack. push ( Frame :: Visit ( child, child_point) ) ;
389+ }
368390 }
369391 }
370392 }
@@ -1000,15 +1022,16 @@ impl<'a> Node<'a> {
10001022 & self ,
10011023 filter : & impl Fn ( & Node ) -> FilterResult ,
10021024 ) -> Option < Node < ' a > > {
1003- for child in self . children ( ) {
1004- let result = filter ( & child) ;
1005- if result == FilterResult :: Include {
1006- return Some ( child) ;
1007- }
1008- if result == FilterResult :: ExcludeNode {
1009- if let Some ( descendant) = child. first_filtered_child ( filter) {
1010- return Some ( descendant) ;
1025+ let mut stack = vec ! [ self . children( ) ] ;
1026+ while let Some ( iter) = stack. last_mut ( ) {
1027+ if let Some ( child) = iter. next ( ) {
1028+ match filter ( & child) {
1029+ FilterResult :: Include => return Some ( child) ,
1030+ FilterResult :: ExcludeNode => stack. push ( child. children ( ) ) ,
1031+ FilterResult :: ExcludeSubtree => { }
10111032 }
1033+ } else {
1034+ stack. pop ( ) ;
10121035 }
10131036 }
10141037 None
@@ -1018,15 +1041,16 @@ impl<'a> Node<'a> {
10181041 & self ,
10191042 filter : & impl Fn ( & Node ) -> FilterResult ,
10201043 ) -> Option < Node < ' a > > {
1021- for child in self . children ( ) . rev ( ) {
1022- let result = filter ( & child) ;
1023- if result == FilterResult :: Include {
1024- return Some ( child) ;
1025- }
1026- if result == FilterResult :: ExcludeNode {
1027- if let Some ( descendant) = child. last_filtered_child ( filter) {
1028- return Some ( descendant) ;
1044+ let mut stack = vec ! [ self . children( ) . rev( ) ] ;
1045+ while let Some ( iter) = stack. last_mut ( ) {
1046+ if let Some ( child) = iter. next ( ) {
1047+ match filter ( & child) {
1048+ FilterResult :: Include => return Some ( child) ,
1049+ FilterResult :: ExcludeNode => stack. push ( child. children ( ) . rev ( ) ) ,
1050+ FilterResult :: ExcludeSubtree => { }
10291051 }
1052+ } else {
1053+ stack. pop ( ) ;
10301054 }
10311055 }
10321056 None
@@ -1085,8 +1109,8 @@ impl<W: fmt::Write> fmt::Write for SpacePrefixingWriter<W> {
10851109#[ cfg( test) ]
10861110mod tests {
10871111 use accesskit:: {
1088- Action , Node , NodeId , Point , Rect , Role , TextDirection , TextPosition , TextSelection , Tree ,
1089- TreeId , TreeUpdate ,
1112+ Action , Affine , Node , NodeId , Point , Rect , Role , TextDirection , TextPosition ,
1113+ TextSelection , Tree , TreeId , TreeUpdate , Vec2 ,
10901114 } ;
10911115 use alloc:: vec;
10921116
@@ -1405,6 +1429,98 @@ mod tests {
14051429 ) ;
14061430 }
14071431
1432+ #[ test]
1433+ fn first_filtered_child ( ) {
1434+ let tree = test_tree ( ) ;
1435+ assert_eq ! (
1436+ Some ( PARAGRAPH_0_ID ) ,
1437+ tree. state( )
1438+ . root( )
1439+ . first_filtered_child( & test_tree_filter)
1440+ . map( |node| node. id( ) . to_components( ) . 0 )
1441+ ) ;
1442+ // Descends through ExcludeNode children (EMPTY_CONTAINER_3_0 then into
1443+ // LINK_3_1) to find the first included descendant.
1444+ assert_eq ! (
1445+ Some ( LABEL_3_1_0_ID ) ,
1446+ tree. state( )
1447+ . node_by_id( nid( PARAGRAPH_3_IGNORED_ID ) )
1448+ . unwrap( )
1449+ . first_filtered_child( & test_tree_filter)
1450+ . map( |node| node. id( ) . to_components( ) . 0 )
1451+ ) ;
1452+ assert ! (
1453+ tree. state( )
1454+ . node_by_id( nid( LABEL_2_0_ID ) )
1455+ . unwrap( )
1456+ . first_filtered_child( & test_tree_filter)
1457+ . is_none( )
1458+ ) ;
1459+ }
1460+
1461+ #[ test]
1462+ fn last_filtered_child ( ) {
1463+ let tree = test_tree ( ) ;
1464+ // Reverse order: skips the trailing ExcludeNode container, returns the
1465+ // included button.
1466+ assert_eq ! (
1467+ Some ( BUTTON_3_2_ID ) ,
1468+ tree. state( )
1469+ . node_by_id( nid( PARAGRAPH_3_IGNORED_ID ) )
1470+ . unwrap( )
1471+ . last_filtered_child( & test_tree_filter)
1472+ . map( |node| node. id( ) . to_components( ) . 0 )
1473+ ) ;
1474+ assert ! (
1475+ tree. state( )
1476+ . node_by_id( nid( LABEL_2_0_ID ) )
1477+ . unwrap( )
1478+ . last_filtered_child( & test_tree_filter)
1479+ . is_none( )
1480+ ) ;
1481+ }
1482+
1483+ #[ test]
1484+ fn transform ( ) {
1485+ let tree = test_tree ( ) ;
1486+ assert_eq ! ( Affine :: IDENTITY , tree. state( ) . root( ) . transform( ) ) ;
1487+ // PARAGRAPH_1_IGNORED defines a translation.
1488+ let expected = Affine :: translate ( Vec2 :: new ( 10.0 , 40.0 ) ) ;
1489+ assert_eq ! (
1490+ expected,
1491+ tree. state( )
1492+ . node_by_id( nid( PARAGRAPH_1_IGNORED_ID ) )
1493+ . unwrap( )
1494+ . transform( )
1495+ ) ;
1496+ // LABEL_1_1 inherits its parent's translation (it has none of its own).
1497+ assert_eq ! (
1498+ expected,
1499+ tree. state( )
1500+ . node_by_id( nid( LABEL_1_1_ID ) )
1501+ . unwrap( )
1502+ . transform( )
1503+ ) ;
1504+ }
1505+
1506+ #[ test]
1507+ fn relative_transform ( ) {
1508+ let tree = test_tree ( ) ;
1509+ let label = tree. state ( ) . node_by_id ( nid ( LABEL_1_1_ID ) ) . unwrap ( ) ;
1510+ let paragraph = tree
1511+ . state ( )
1512+ . node_by_id ( nid ( PARAGRAPH_1_IGNORED_ID ) )
1513+ . unwrap ( ) ;
1514+ // Relative to its immediate (transformed) parent: identity, since the
1515+ // parent's transform is excluded.
1516+ assert_eq ! ( Affine :: IDENTITY , label. relative_transform( & paragraph) ) ;
1517+ // Relative to the root: includes the parent's translation.
1518+ assert_eq ! (
1519+ Affine :: translate( Vec2 :: new( 10.0 , 40.0 ) ) ,
1520+ label. relative_transform( & tree. state( ) . root( ) )
1521+ ) ;
1522+ }
1523+
14081524 #[ test]
14091525 fn no_label_or_labelled_by ( ) {
14101526 let update = TreeUpdate {
0 commit comments