6
6
part of engine;
7
7
8
8
/// Set this flag to `true` to cause the engine to visualize the semantics tree
9
- /// on the screen.
9
+ /// on the screen for debugging .
10
10
///
11
- /// This is useful for debugging.
12
- const bool _debugShowSemanticsNodes = false ;
11
+ /// This only works in profile and release modes. Debug mode does not support
12
+ /// passing compile-time constants.
13
+ ///
14
+ /// Example:
15
+ ///
16
+ /// ```
17
+ /// flutter run -d chrome --profile --dart-define=FLUTTER_WEB_DEBUG_SHOW_SEMANTICS=true
18
+ /// ```
19
+ const bool _debugShowSemanticsNodes = bool .fromEnvironment (
20
+ 'FLUTTER_WEB_DEBUG_SHOW_SEMANTICS' ,
21
+ defaultValue: false ,
22
+ );
13
23
14
24
/// Contains updates for the semantics tree.
15
25
///
@@ -233,27 +243,29 @@ class SemanticsObject {
233
243
/// Creates a semantics tree node with the given [id] and [owner] .
234
244
SemanticsObject (this .id, this .owner) {
235
245
// DOM nodes created for semantics objects are positioned absolutely using
236
- // transforms. We use a transparent color instead of "visibility:hidden" or
237
- // "display:none" so that a screen reader does not ignore these elements.
246
+ // transforms.
238
247
element.style.position = 'absolute' ;
239
248
240
249
// The root node has some properties that other nodes do not.
241
- if (id == 0 ) {
250
+ if (id == 0 && ! _debugShowSemanticsNodes ) {
242
251
// Make all semantics transparent. We use `filter` instead of `opacity`
243
252
// attribute because `filter` is stronger. `opacity` does not apply to
244
253
// some elements, particularly on iOS, such as the slider thumb and track.
254
+ //
255
+ // We use transparency instead of "visibility:hidden" or "display:none"
256
+ // so that a screen reader does not ignore these elements.
245
257
element.style.filter = 'opacity(0%)' ;
246
258
247
259
// Make text explicitly transparent to signal to the browser that no
248
260
// rasterization needs to be done.
249
261
element.style.color = 'rgba(0,0,0,0)' ;
250
262
}
251
263
264
+ // Make semantic elements visible for debugging by outlining them using a
265
+ // green border. We do not use `border` attribute because it affects layout
266
+ // (`outline` does not).
252
267
if (_debugShowSemanticsNodes) {
253
- element.style
254
- ..filter = 'opacity(90%)'
255
- ..outline = '1px solid green'
256
- ..color = 'purple' ;
268
+ element.style.outline = '1px solid green' ;
257
269
}
258
270
}
259
271
@@ -853,9 +865,9 @@ class SemanticsObject {
853
865
hasIdentityTransform &&
854
866
verticalContainerAdjustment == 0.0 &&
855
867
horizontalContainerAdjustment == 0.0 ) {
856
- _resetElementOffsets (element);
868
+ _clearSemanticElementTransform (element);
857
869
if (containerElement != null ) {
858
- _resetElementOffsets (containerElement);
870
+ _clearSemanticElementTransform (containerElement);
859
871
}
860
872
return ;
861
873
}
@@ -879,81 +891,48 @@ class SemanticsObject {
879
891
effectiveTransformIsIdentity = false ;
880
892
}
881
893
882
- if (! effectiveTransformIsIdentity || isMacOrIOS) {
883
- if (effectiveTransformIsIdentity) {
884
- effectiveTransform = Matrix4 .identity ();
885
- }
886
- if (isDesktop) {
887
- element.style
888
- ..transformOrigin = '0 0 0'
889
- ..transform = (effectiveTransformIsIdentity ? 'translate(0px 0px 0px)'
890
- : matrix4ToCssTransform (effectiveTransform));
891
- } else {
892
- // Mobile screen readers observed to have errors while calculating the
893
- // semantics focus borders if css `transform` properties are used.
894
- // See: https://github.com/flutter/flutter/issues/68225
895
- // Therefore we are calculating a bounding rectangle for the
896
- // effective transform and use that rectangle to set TLWH css style
897
- // properties.
898
- // Note: Identity matrix is not using this code path.
899
- final ui.Rect rect =
900
- computeBoundingRectangleFromMatrix (effectiveTransform, _rect! );
901
- element.style
902
- ..top = '${rect .top }px'
903
- ..left = '${rect .left }px'
904
- ..width = '${rect .width }px'
905
- ..height = '${rect .height }px' ;
906
- }
894
+ if (! effectiveTransformIsIdentity) {
895
+ element.style
896
+ ..transformOrigin = '0 0 0'
897
+ ..transform = matrix4ToCssTransform (effectiveTransform);
907
898
} else {
908
- _resetElementOffsets (element);
909
- // TODO: https://github.com/flutter/flutter/issues/73347
899
+ _clearSemanticElementTransform (element);
910
900
}
911
901
912
902
if (containerElement != null ) {
913
903
if (! hasZeroRectOffset ||
914
- isMacOrIOS ||
915
904
verticalContainerAdjustment != 0.0 ||
916
905
horizontalContainerAdjustment != 0.0 ) {
917
906
final double translateX = - _rect! .left + horizontalContainerAdjustment;
918
907
final double translateY = - _rect! .top + verticalContainerAdjustment;
919
- if (isDesktop) {
920
- containerElement.style
921
- ..transformOrigin = '0 0 0'
922
- ..transform = 'translate(${translateX }px, ${translateY }px)' ;
923
- } else {
924
- containerElement.style
925
- ..top = '${translateY }px'
926
- ..left = '${translateX }px' ;
927
- }
908
+ containerElement.style
909
+ ..top = '${translateY }px'
910
+ ..left = '${translateX }px' ;
928
911
} else {
929
- _resetElementOffsets (containerElement);
912
+ _clearSemanticElementTransform (containerElement);
930
913
}
931
914
}
932
915
}
933
916
934
- // On Mac OS and iOS, VoiceOver requires left=0 top=0 value to correctly
935
- // handle order. See https://github.com/flutter/flutter/issues/73347.
936
- static void _resetElementOffsets (html.Element element) {
917
+ /// Clears the transform on a semantic element as if an identity transform is
918
+ /// applied.
919
+ ///
920
+ /// On macOS and iOS, VoiceOver requires `left=0; top=0` value to correctly
921
+ /// handle traversal order.
922
+ ///
923
+ /// See https://github.com/flutter/flutter/issues/73347.
924
+ static void _clearSemanticElementTransform (html.Element element) {
925
+ element.style
926
+ ..removeProperty ('transform-origin' )
927
+ ..removeProperty ('transform' );
937
928
if (isMacOrIOS) {
938
- if (isDesktop) {
939
- element.style
940
- ..transformOrigin = '0 0 0'
941
- ..transform = 'translate(0px, 0px)' ;
942
- } else {
943
- element.style
944
- ..top = '0px'
945
- ..left = '0px' ;
946
- }
929
+ element.style
930
+ ..top = '0px'
931
+ ..left = '0px' ;
947
932
} else {
948
- if (isDesktop) {
949
- element.style
950
- ..removeProperty ('transform-origin' )
951
- ..removeProperty ('transform' );
952
- } else {
953
- element.style
954
- ..removeProperty ('top' )
955
- ..removeProperty ('left' );
956
- }
933
+ element.style
934
+ ..removeProperty ('top' )
935
+ ..removeProperty ('left' );
957
936
}
958
937
}
959
938
@@ -1493,7 +1472,10 @@ class EngineSemanticsOwner {
1493
1472
/// Updates the semantics tree from data in the [uiUpdate] .
1494
1473
void updateSemantics (ui.SemanticsUpdate uiUpdate) {
1495
1474
if (! _semanticsEnabled) {
1496
- return ;
1475
+ // If we're receiving a semantics update from the framework, it means the
1476
+ // developer enabled it programmatically, so we enable it in the engine
1477
+ // too.
1478
+ semanticsEnabled = true ;
1497
1479
}
1498
1480
1499
1481
final SemanticsUpdate update = uiUpdate as SemanticsUpdate ;
@@ -1505,19 +1487,7 @@ class EngineSemanticsOwner {
1505
1487
if (_rootSemanticsElement == null ) {
1506
1488
final SemanticsObject root = _semanticsTree[0 ]! ;
1507
1489
_rootSemanticsElement = root.element;
1508
- // We render semantics inside the glasspane for proper focus and event
1509
- // handling. If semantics is behind the glasspane, the phone will disable
1510
- // focusing by touch, only by tabbing around the UI. If semantics is in
1511
- // front of glasspane, then DOM event won't bubble up to the glasspane so
1512
- // it can forward events to the framework.
1513
- //
1514
- // We insert the semantics root before the scene host. For all widgets
1515
- // in the scene, except for platform widgets, the scene host will pass the
1516
- // pointer events through to the semantics tree. However, for platform
1517
- // views, the pointer events will not pass through, and will be handled
1518
- // by the platform view.
1519
- domRenderer.glassPaneElement!
1520
- .insertBefore (_rootSemanticsElement! , domRenderer.sceneHostElement);
1490
+ domRenderer.semanticsHostElement! .append (root.element);
1521
1491
}
1522
1492
1523
1493
_finalizeTree ();
0 commit comments