Skip to content

Commit 9b34207

Browse files
author
nturgut
authored
Fixing semantics borders on mobile web (flutter#21856)
* logging * fixing positions with wrong a11y borders screenreader-on/mobile browsers * remove logs from the window class * work on unit tests * using reviewer suggestion for translations * compute bounding matrix * compute bounding matrix * addding more comments * reenable failing test case
1 parent 6a331d3 commit 9b34207

File tree

2 files changed

+108
-17
lines changed

2 files changed

+108
-17
lines changed

lib/web_ui/lib/src/engine/semantics/semantics.dart

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -851,13 +851,25 @@ class SemanticsObject {
851851
hasIdentityTransform &&
852852
verticalContainerAdjustment == 0.0 &&
853853
horizontalContainerAdjustment == 0.0) {
854-
element.style
855-
..removeProperty('transform-origin')
856-
..removeProperty('transform');
857-
if (containerElement != null) {
858-
containerElement.style
854+
if (isDesktop) {
855+
element.style
859856
..removeProperty('transform-origin')
860857
..removeProperty('transform');
858+
} else {
859+
element.style
860+
..removeProperty('top')
861+
..removeProperty('left');
862+
}
863+
if (containerElement != null) {
864+
if (isDesktop) {
865+
containerElement.style
866+
..removeProperty('transform-origin')
867+
..removeProperty('transform');
868+
} else {
869+
containerElement.style
870+
..removeProperty('top')
871+
..removeProperty('left');
872+
}
861873
}
862874
return;
863875
}
@@ -882,13 +894,36 @@ class SemanticsObject {
882894
}
883895

884896
if (!effectiveTransformIsIdentity) {
885-
element.style
886-
..transformOrigin = '0 0 0'
887-
..transform = matrix4ToCssTransform(effectiveTransform);
897+
if (isDesktop) {
898+
element.style
899+
..transformOrigin = '0 0 0'
900+
..transform = matrix4ToCssTransform(effectiveTransform);
901+
} else {
902+
// Mobile screen readers observed to have errors while calculating the
903+
// semantics focus borders if css `transform` properties are used.
904+
// See: https://github.com/flutter/flutter/issues/68225
905+
// Therefore we are calculating a bounding rectangle for the
906+
// effective transform and use that rectangle to set TLWH css style
907+
// properties.
908+
// Note: Identity matrix is not using this code path.
909+
final ui.Rect rect =
910+
computeBoundingRectangleFromMatrix(effectiveTransform, _rect!);
911+
element.style
912+
..top = '${rect.top}px'
913+
..left = '${rect.left}px'
914+
..width = '${rect.width}px'
915+
..height = '${rect.height}px';
916+
}
888917
} else {
889-
element.style
890-
..removeProperty('transform-origin')
891-
..removeProperty('transform');
918+
if (isDesktop) {
919+
element.style
920+
..removeProperty('transform-origin')
921+
..removeProperty('transform');
922+
} else {
923+
element.style
924+
..removeProperty('top')
925+
..removeProperty('left');
926+
}
892927
}
893928

894929
if (containerElement != null) {
@@ -897,13 +932,25 @@ class SemanticsObject {
897932
horizontalContainerAdjustment != 0.0) {
898933
final double translateX = -_rect!.left + horizontalContainerAdjustment;
899934
final double translateY = -_rect!.top + verticalContainerAdjustment;
900-
containerElement.style
901-
..transformOrigin = '0 0 0'
902-
..transform = 'translate(${translateX}px, ${translateY}px)';
935+
if (isDesktop) {
936+
containerElement.style
937+
..transformOrigin = '0 0 0'
938+
..transform = 'translate(${translateX}px, ${translateY}px)';
939+
} else {
940+
containerElement.style
941+
..top = '${translateY}px'
942+
..left = '${translateX}px';
943+
}
903944
} else {
904-
containerElement.style
905-
..removeProperty('transform-origin')
906-
..removeProperty('transform');
945+
if (isDesktop) {
946+
containerElement.style
947+
..removeProperty('transform-origin')
948+
..removeProperty('transform');
949+
} else {
950+
containerElement.style
951+
..removeProperty('top')
952+
..removeProperty('left');
953+
}
907954
}
908955
}
909956
}

lib/web_ui/lib/src/engine/util.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,3 +596,47 @@ int clampInt(int value, int min, int max) {
596596
return value;
597597
}
598598
}
599+
600+
ui.Rect computeBoundingRectangleFromMatrix(Matrix4 transform, ui.Rect rect) {
601+
final Float32List m = transform.storage;
602+
// Apply perspective transform to all 4 corners. Can't use left,top, bottom,
603+
// right since for example rotating 45 degrees would yield inaccurate size.
604+
double x = rect.left;
605+
double y = rect.top;
606+
double wp = 1.0 / ((m[3] * x) + (m[7] * y) + m[15]);
607+
double xp = ((m[0] * x) + (m[4] * y) + m[12]) * wp;
608+
double yp = ((m[1] * x) + (m[5] * y) + m[13]) * wp;
609+
double minX = xp, maxX = xp;
610+
double minY =yp, maxY = yp;
611+
x = rect.right;
612+
y = rect.bottom;
613+
wp = 1.0 / ((m[3] * x) + (m[7] * y) + m[15]);
614+
xp = ((m[0] * x) + (m[4] * y) + m[12]) * wp;
615+
yp = ((m[1] * x) + (m[5] * y) + m[13]) * wp;
616+
617+
minX = math.min(minX, xp);
618+
maxX = math.max(maxX, xp);
619+
minY = math.min(minY, yp);
620+
maxY = math.max(maxY, yp);
621+
622+
x = rect.left;
623+
y = rect.bottom;
624+
wp = 1.0 / ((m[3] * x) + (m[7] * y) + m[15]);
625+
xp = ((m[0] * x) + (m[4] * y) + m[12]) * wp;
626+
yp = ((m[1] * x) + (m[5] * y) + m[13]) * wp;
627+
minX = math.min(minX, xp);
628+
maxX = math.max(maxX, xp);
629+
minY = math.min(minY, yp);
630+
maxY = math.max(maxY, yp);
631+
632+
x = rect.right;
633+
y = rect.top;
634+
wp = 1.0 / ((m[3] * x) + (m[7] * y) + m[15]);
635+
xp = ((m[0] * x) + (m[4] * y) + m[12]) * wp;
636+
yp = ((m[1] * x) + (m[5] * y) + m[13]) * wp;
637+
minX = math.min(minX, xp);
638+
maxX = math.max(maxX, xp);
639+
minY = math.min(minY, yp);
640+
maxY = math.max(maxY, yp);
641+
return ui.Rect.fromLTWH(minX, minY, maxX-minX, maxY-minY);
642+
}

0 commit comments

Comments
 (0)