@@ -1431,18 +1431,74 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
1431
1431
}
1432
1432
}
1433
1433
1434
- /// A helper class to contain a semantics node and the effective
1435
- /// sort order of that node during the traversal of the tree. This is
1436
- /// what is actually sorted when semantics nodes are sorted.
1434
+ /// This class defines the comparison that is used to sort [SemanticsNode] s
1435
+ /// before sending them to the platform side.
1436
+ ///
1437
+ /// This is a helper class used to contain a [node] , the effective
1438
+ /// [order] , the globally transformed starting corner [globalStartCorner] ,
1439
+ /// and the containing node's [containerTextDirection] during the traversal of
1440
+ /// the semantics node tree. A null value is allowed for [containerTextDirection] ,
1441
+ /// because in that case we want to fall back to ordering by child insertion
1442
+ /// order for nodes that are equal after sorting from top to bottom.
1437
1443
class _TraversalSortNode implements Comparable <_TraversalSortNode > {
1438
- _TraversalSortNode (this .node, this .order);
1444
+ _TraversalSortNode (this .node, this .order, this .containerTextDirection, Matrix4 transform)
1445
+ : assert (node != null ) {
1446
+ // When containerTextDirection is null, this is set to topLeft, but the x
1447
+ // coordinate is also ignored when doing the comparison in that case, so
1448
+ // this isn't actually expressing a directionality opinion.
1449
+ globalStartCorner = _transformPoint (
1450
+ containerTextDirection == TextDirection .rtl ? node.rect.topRight : node.rect.topLeft,
1451
+ transform,
1452
+ );
1453
+ }
1454
+
1455
+ /// The node that this sort node represents.
1439
1456
SemanticsNode node;
1457
+
1458
+ /// The effective text direction for this node is the directionality that
1459
+ /// its container has.
1460
+ TextDirection containerTextDirection;
1461
+
1462
+ /// This is the effective sort order for this node, taking into account its
1463
+ /// parents.
1440
1464
SemanticsSortOrder order;
1441
1465
1466
+ /// The is the starting corner for the rectangle on this semantics node in
1467
+ /// global coordinates. When the container has the directionality
1468
+ /// [TextDirection.ltr] , this is the upper left corner. When the container
1469
+ /// has the directionality [TextDirection.rtl] , this is the upper right
1470
+ /// corner. When the container has no directionality, this is set, but the
1471
+ /// x coordinate is ignored.
1472
+ Offset globalStartCorner;
1473
+
1474
+ static Offset _transformPoint (Offset point, Matrix4 matrix) {
1475
+ final Vector3 result = matrix.transform3 (new Vector3 (point.dx, point.dy, 0.0 ));
1476
+ return new Offset (result.x, result.y);
1477
+ }
1478
+
1479
+ /// Compares the node's start corner with that of `other` .
1480
+ ///
1481
+ /// Sorts top to bottom, and then start to end.
1482
+ ///
1483
+ /// This takes into account the container text direction, since the
1484
+ /// coordinate system has zero on the left, and we need to compare
1485
+ /// differently for different text directions.
1486
+ ///
1487
+ /// If no text direction is available (i.e. [containerTextDirection] is
1488
+ /// null), then we sort by vertical position first, and then by child
1489
+ /// insertion order.
1442
1490
int _compareGeometry (_TraversalSortNode other) {
1443
- // TODO(gspencer): Move the geometric comparison from the platform side to here.
1444
- // This involves calculating the globally-transformed quad for the semantics node rect
1445
- // and then sorting by its bounding box, based on the container's directionality.
1491
+ final int verticalDiff = globalStartCorner.dy.compareTo (other.globalStartCorner.dy);
1492
+ if (verticalDiff != 0 ) {
1493
+ return verticalDiff;
1494
+ }
1495
+ switch (containerTextDirection) {
1496
+ case TextDirection .rtl:
1497
+ return other.globalStartCorner.dx.compareTo (globalStartCorner.dx);
1498
+ case TextDirection .ltr:
1499
+ return globalStartCorner.dx.compareTo (other.globalStartCorner.dx);
1500
+ }
1501
+ // In case containerTextDirection is null we fall back to child insertion order.
1446
1502
return 0 ;
1447
1503
}
1448
1504
@@ -1490,17 +1546,34 @@ class SemanticsOwner extends ChangeNotifier {
1490
1546
void _updateTraversalOrder () {
1491
1547
final List <_TraversalSortNode > nodesInSemanticsTraversalOrder = < _TraversalSortNode > [];
1492
1548
SemanticsSortOrder currentSortOrder = new SemanticsSortOrder (keys: < SemanticsSortKey > []);
1549
+ Matrix4 currentTransform = new Matrix4 .identity ();
1550
+ TextDirection currentTextDirection = rootSemanticsNode.textDirection;
1493
1551
bool visitor (SemanticsNode node) {
1494
1552
final SemanticsSortOrder previousOrder = currentSortOrder;
1553
+ final Matrix4 previousTransform = currentTransform.clone ();
1495
1554
if (node.sortOrder != null ) {
1496
1555
currentSortOrder = currentSortOrder.merge (node.sortOrder);
1497
1556
}
1498
- final _TraversalSortNode traversalNode = new _TraversalSortNode (node, currentSortOrder);
1557
+ if (node.transform != null ) {
1558
+ currentTransform.multiply (node.transform);
1559
+ }
1560
+ final _TraversalSortNode traversalNode = new _TraversalSortNode (
1561
+ node,
1562
+ currentSortOrder,
1563
+ currentTextDirection,
1564
+ currentTransform,
1565
+ );
1566
+ // The text direction in force here is the parent's text direction.
1499
1567
nodesInSemanticsTraversalOrder.add (traversalNode);
1500
1568
if (node.hasChildren) {
1569
+ final TextDirection previousTextDirection = currentTextDirection;
1570
+ currentTextDirection = node.textDirection;
1571
+ // Now visit the children with this node's text direction in force.
1501
1572
node.visitChildren (visitor);
1573
+ currentTextDirection = previousTextDirection;
1502
1574
}
1503
1575
currentSortOrder = previousOrder;
1576
+ currentTransform = previousTransform;
1504
1577
return true ;
1505
1578
}
1506
1579
rootSemanticsNode.visitChildren (visitor);
@@ -2522,7 +2595,9 @@ String _concatStrings({
2522
2595
/// of keys can co-exist at the same level and not interfere with each other,
2523
2596
/// allowing for sorting into groups. Keys that evaluate as equal, or when
2524
2597
/// compared with Widgets that don't have [Semantics] , fall back to the default
2525
- /// upper-start-to-lower-end geometric ordering.
2598
+ /// upper-start-to-lower-end geometric ordering if a text directionality
2599
+ /// exists, and they sort from top to bottom followed by child insertion order
2600
+ /// when no directionality is present.
2526
2601
///
2527
2602
/// Since widgets are globally sorted by their sort key, the order does not have
2528
2603
/// to conform to the widget hierarchy.
0 commit comments