diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index e15542bf5ca6ea70889264d138edb71107795f8a..a7095ebc0d1367767fd7bfee98b5178a4b482c9b 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -203,7 +203,8 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass2 { /// asynchronously, the [Window.onSemanticsAction] callback might be called /// with an action that is no longer possible. /// - /// The `label` is a string that describes this node. + /// The `label` is a string that describes this node. Its reading direction is + /// given by `textDirection`. /// /// The `rect` is the region occupied by this node in its own coordinate /// system. @@ -216,6 +217,7 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass2 { int actions, Rect rect, String label, + TextDirection textDirection, Float64List transform, Int32List children }) { @@ -229,6 +231,7 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass2 { rect.right, rect.bottom, label, + textDirection != null ? textDirection.index + 1 : 0, transform, children); } @@ -241,6 +244,7 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass2 { double right, double bottom, String label, + int textDirection, Float64List transform, Int32List children ) native "SemanticsUpdateBuilder_updateNode"; diff --git a/lib/ui/semantics/semantics_node.h b/lib/ui/semantics/semantics_node.h index 0dd6e3dd3b858bc378fb2fcbeae831a22af8313e..6eb18bacf6fa28d4034fbbf9eb7ff49938e5b32c 100644 --- a/lib/ui/semantics/semantics_node.h +++ b/lib/ui/semantics/semantics_node.h @@ -45,6 +45,8 @@ struct SemanticsNode { int32_t flags = 0; int32_t actions = 0; std::string label; + int32_t textDirection = 0; // 0=unknown, 1=rtl, 2=ltr + SkRect rect = SkRect::MakeEmpty(); SkMatrix44 transform = SkMatrix44(SkMatrix44::kIdentity_Constructor); std::vector children; diff --git a/lib/ui/semantics/semantics_update_builder.cc b/lib/ui/semantics/semantics_update_builder.cc index c193223ef6537134858497fae21e99777eb7543e..4f06191920177475831a2859b3c81c922fdb3ffd 100644 --- a/lib/ui/semantics/semantics_update_builder.cc +++ b/lib/ui/semantics/semantics_update_builder.cc @@ -42,6 +42,7 @@ void SemanticsUpdateBuilder::updateNode(int id, double right, double bottom, std::string label, + int textDirection, const tonic::Float64List& transform, const tonic::Int32List& children) { SemanticsNode node; @@ -50,6 +51,7 @@ void SemanticsUpdateBuilder::updateNode(int id, node.actions = actions; node.rect = SkRect::MakeLTRB(left, top, right, bottom); node.label = label; + node.textDirection = textDirection; node.transform.setColMajord(transform.data()); node.children = std::vector( children.data(), children.data() + children.num_elements()); diff --git a/lib/ui/semantics/semantics_update_builder.h b/lib/ui/semantics/semantics_update_builder.h index 40f2fe9464e55663bf564eb8aadc8218c9ae6377..542955df057c65a2dfc18185029525a7cfe8c996 100644 --- a/lib/ui/semantics/semantics_update_builder.h +++ b/lib/ui/semantics/semantics_update_builder.h @@ -33,6 +33,7 @@ class SemanticsUpdateBuilder double right, double bottom, std::string label, + int textDirection, const tonic::Float64List& transform, const tonic::Int32List& children); diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index d01affa33a0942f6303fbb3b631cb960bab1e019..e509bee8ef0f7429b3abbfd50734331865fdcabb 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -190,7 +190,7 @@ class AccessibilityBridge extends AccessibilityNodeProvider { if ((object.actions & SEMANTICS_ACTION_SCROLL_UP) != 0) { mOwner.dispatchSemanticsAction(virtualViewId, SEMANTICS_ACTION_SCROLL_UP); } else if ((object.actions & SEMANTICS_ACTION_SCROLL_LEFT) != 0) { - // TODO(ianh): bidi support + // TODO(ianh): bidi support using textDirection mOwner.dispatchSemanticsAction(virtualViewId, SEMANTICS_ACTION_SCROLL_LEFT); } else if ((object.actions & SEMANTICS_ACTION_INCREASE) != 0) { mOwner.dispatchSemanticsAction(virtualViewId, SEMANTICS_ACTION_INCREASE); @@ -203,7 +203,7 @@ class AccessibilityBridge extends AccessibilityNodeProvider { if ((object.actions & SEMANTICS_ACTION_SCROLL_DOWN) != 0) { mOwner.dispatchSemanticsAction(virtualViewId, SEMANTICS_ACTION_SCROLL_DOWN); } else if ((object.actions & SEMANTICS_ACTION_SCROLL_RIGHT) != 0) { - // TODO(ianh): bidi support + // TODO(ianh): bidi support using textDirection mOwner.dispatchSemanticsAction(virtualViewId, SEMANTICS_ACTION_SCROLL_RIGHT); } else if ((object.actions & SEMANTICS_ACTION_DECREASE) != 0) { mOwner.dispatchSemanticsAction(virtualViewId, SEMANTICS_ACTION_DECREASE); @@ -347,6 +347,20 @@ class AccessibilityBridge extends AccessibilityNodeProvider { sendAccessibilityEvent(0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); } + private enum TextDirection { + UNKNOWN, LTR, RTL; + + public static TextDirection fromInt(int value) { + switch (value) { + case 1: + return RTL; + case 2: + return LTR; + } + return UNKNOWN; + } + } + private class SemanticsObject { SemanticsObject() { } @@ -355,6 +369,7 @@ class AccessibilityBridge extends AccessibilityNodeProvider { int flags; int actions; String label; + TextDirection textDirection; private float left; private float top; @@ -394,6 +409,8 @@ class AccessibilityBridge extends AccessibilityNodeProvider { else label = strings[stringIndex]; + textDirection = TextDirection.fromInt(buffer.getInt()); + left = buffer.getFloat(); top = buffer.getFloat(); right = buffer.getFloat(); diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index 6d4ca29bdc55ff076efca68f17427e3a1a6ddfd6..3bc57ca87fbdd398b9e6ab045681ab918f4ea904 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -421,7 +421,7 @@ bool PlatformViewAndroid::ResourceContextMakeCurrent() { void PlatformViewAndroid::UpdateSemantics( std::vector update) { - constexpr size_t kBytesPerNode = 25 * sizeof(int32_t); + constexpr size_t kBytesPerNode = 26 * sizeof(int32_t); constexpr size_t kBytesPerChild = sizeof(int32_t); JNIEnv* env = fml::jni::AttachCurrentThread(); @@ -443,6 +443,8 @@ void PlatformViewAndroid::UpdateSemantics( std::vector strings; size_t position = 0; for (const blink::SemanticsNode& node : update) { + // If you edit this code, make sure you update kBytesPerNode + // above to match the number of values you are sending. buffer_int32[position++] = node.id; buffer_int32[position++] = node.flags; buffer_int32[position++] = node.actions; @@ -452,6 +454,7 @@ void PlatformViewAndroid::UpdateSemantics( buffer_int32[position++] = strings.size(); strings.push_back(node.label); } + buffer_int32[position++] = node.textDirection; buffer_float32[position++] = node.rect.left(); buffer_float32[position++] = node.rect.top(); buffer_float32[position++] = node.rect.right(); diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index 6feeaa27c5a4d6ee21edbd54c6650375068d7cbf..3e85619b57645e5d34e390ad54fe2a2b5aafad67 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -23,10 +23,10 @@ blink::SemanticsAction GetSemanticsActionForScrollDirection( // directions, which is why the following maps left to right and vice versa. switch (direction) { case UIAccessibilityScrollDirectionRight: - case UIAccessibilityScrollDirectionPrevious: // TODO(abarth): Support RTL. + case UIAccessibilityScrollDirectionPrevious: // TODO(abarth): Support RTL using _node.textDirection. return blink::SemanticsAction::kScrollLeft; case UIAccessibilityScrollDirectionLeft: - case UIAccessibilityScrollDirectionNext: // TODO(abarth): Support RTL. + case UIAccessibilityScrollDirectionNext: // TODO(abarth): Support RTL using _node.textDirection. return blink::SemanticsAction::kScrollRight; case UIAccessibilityScrollDirectionUp: return blink::SemanticsAction::kScrollDown;