Fixes Text contrast test rect check (#112492)

diff --git a/packages/flutter_test/lib/src/accessibility.dart b/packages/flutter_test/lib/src/accessibility.dart
index 53bc01e..5dc9941 100644
--- a/packages/flutter_test/lib/src/accessibility.dart
+++ b/packages/flutter_test/lib/src/accessibility.dart
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:typed_data';
 import 'dart:ui' as ui;
 
+import 'package:flutter/foundation.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
@@ -350,7 +350,7 @@
     late bool isBold;
     double? fontSize;
 
-    late final Rect paintBounds;
+    late final Rect screenBounds;
     late final Rect paintBoundsWithOffset;
 
     final RenderObject? renderBox = element.renderObject;
@@ -358,21 +358,26 @@
       throw StateError('Unexpected renderObject type: $renderBox');
     }
 
-    const Offset offset = Offset(4.0, 4.0);
-    paintBoundsWithOffset = Rect.fromPoints(
-      renderBox.localToGlobal(renderBox.paintBounds.topLeft - offset),
-      renderBox.localToGlobal(renderBox.paintBounds.bottomRight + offset),
-    );
+    final Matrix4 globalTransform = renderBox.getTransformTo(null);
+    paintBoundsWithOffset = MatrixUtils.transformRect(globalTransform, renderBox.paintBounds.inflate(4.0));
 
-    paintBounds = Rect.fromPoints(
-      renderBox.localToGlobal(renderBox.paintBounds.topLeft),
-      renderBox.localToGlobal(renderBox.paintBounds.bottomRight),
-    );
-
-    final Offset? nodeOffset = node.transform != null ? MatrixUtils.getAsTranslation(node.transform!) : null;
-
-    final Rect nodeBounds = node.rect.shift(nodeOffset ?? Offset.zero);
-    final Rect intersection = nodeBounds.intersect(paintBounds);
+    // The semantics node transform will include root view transform, which is
+    // not included in renderBox.getTransformTo(null). Manually multiply the
+    // root transform to the global transform.
+    final Matrix4 rootTransform = Matrix4.identity();
+    tester.binding.renderView.applyPaintTransform(tester.binding.renderView.child!, rootTransform);
+    rootTransform.multiply(globalTransform);
+    screenBounds = MatrixUtils.transformRect(rootTransform, renderBox.paintBounds);
+    Rect nodeBounds = node.rect;
+    SemanticsNode? current = node;
+    while (current != null) {
+      final Matrix4? transform = current.transform;
+      if (transform != null) {
+        nodeBounds = MatrixUtils.transformRect(transform, nodeBounds);
+      }
+      current = current.parent;
+    }
+    final Rect intersection = nodeBounds.intersect(screenBounds);
     if (intersection.width <= 0 || intersection.height <= 0) {
       // Skip this element since it doesn't correspond to the given semantic
       // node.
diff --git a/packages/flutter_test/test/accessibility_test.dart b/packages/flutter_test/test/accessibility_test.dart
index a8aee69..78d4ecf 100644
--- a/packages/flutter_test/test/accessibility_test.dart
+++ b/packages/flutter_test/test/accessibility_test.dart
@@ -225,6 +225,37 @@
       handle.dispose();
     });
 
+    testWidgets('Correctly identify failures in complex transforms', (WidgetTester tester) async {
+      final SemanticsHandle handle = tester.ensureSemantics();
+      await tester.pumpWidget(
+        _boilerplate(
+          Padding(
+            padding: const EdgeInsets.only(left: 100),
+            child: Semantics(
+              container: true,
+              child: Padding(
+                padding: const EdgeInsets.only(left: 100),
+                child: Semantics(
+                  container: true,
+                  child: Container(
+                    width: 100.0,
+                    height: 200.0,
+                    color: Colors.amberAccent,
+                    child: const Text(
+                      'this',
+                      style: TextStyle(color: Colors.amber),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+      await expectLater(tester, doesNotMeetGuideline(textContrastGuideline));
+      handle.dispose();
+    });
+
     testWidgets('Material text field - default style',
         (WidgetTester tester) async {
       final SemanticsHandle handle = tester.ensureSemantics();