diff --git a/DEPS b/DEPS index 2ec7cd49..42d81d66 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ deps = { 'src/third_party/libcxx': 'https://llvm.googlesource.com/llvm-project/libcxx@bd557f6f764d1e40b62528a13b124ce740624f8f', 'src/third_party/libcxxabi': 'https://llvm.googlesource.com/llvm-project/libcxxabi@a4dda1589d37a7e4b4f7a81ebad01b1083f2e726', 'src/third_party/googletest': 'https://github.com/google/googletest@7f036c5563af7d0329f20e8bb42effb04629f0c0', - 'src/third_party/dart': 'https://dart.googlesource.com/sdk.git@2da4111d8d0cbf2a83c0662251508f017000da8a', + 'src/third_party/dart': 'https://dart.googlesource.com/sdk.git@e927f58e327ae13d056a16bb2ebf618e071c20a7', 'src/third_party/clang': { 'packages': [ { diff --git a/flutter/shell/platform/common/accessibility_bridge.cc b/flutter/shell/platform/common/accessibility_bridge.cc index 70934026..ca318e1f 100644 --- a/flutter/shell/platform/common/accessibility_bridge.cc +++ b/flutter/shell/platform/common/accessibility_bridge.cc @@ -524,6 +524,13 @@ void AccessibilityBridge::SetStringListAttributesFromFlutterUpdate( } } +void AccessibilityBridge::SetIdentifierFromFlutterUpdate( + ui::AXNodeData& node_data, + const SemanticsNode& node) { + node_data.AddStringAttribute(ax::mojom::StringAttribute::kIdentifier, + node.identifier); +} + void AccessibilityBridge::SetNameFromFlutterUpdate(ui::AXNodeData& node_data, const SemanticsNode& node) { node_data.SetName(node.label); @@ -635,6 +642,9 @@ AccessibilityBridge::FromFlutterSemanticsNode( flutter_node.custom_accessibility_actions + flutter_node.custom_accessibility_actions_count); } + if (flutter_node.identifier) { + result.identifier = std::string(flutter_node.identifier); + } return result; } diff --git a/flutter/shell/platform/common/accessibility_bridge.h b/flutter/shell/platform/common/accessibility_bridge.h index 9028aa32..334eb26a 100644 --- a/flutter/shell/platform/common/accessibility_bridge.h +++ b/flutter/shell/platform/common/accessibility_bridge.h @@ -182,6 +182,7 @@ class AccessibilityBridge std::vector children_in_traversal_order; std::vector custom_accessibility_actions; int32_t heading_level; + std::string identifier; } SemanticsNode; // See FlutterSemanticsCustomAction in embedder.h @@ -226,6 +227,8 @@ class AccessibilityBridge const SemanticsNode& node); void SetStringListAttributesFromFlutterUpdate(ui::AXNodeData& node_data, const SemanticsNode& node); + void SetIdentifierFromFlutterUpdate(ui::AXNodeData& node_data, + const SemanticsNode& node); void SetNameFromFlutterUpdate(ui::AXNodeData& node_data, const SemanticsNode& node); void SetValueFromFlutterUpdate(ui::AXNodeData& node_data, diff --git a/flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h b/flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h index e6eacad6..905ad222 100644 --- a/flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h +++ b/flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -216,6 +217,23 @@ class EncodableValue : public internal::EncodableValueVariant { return std::get(*this); } + // Convenience method to simplify handling objects received from Flutter + // where the values may be larger than 32-bit, since they have the same type + // on the Dart side, but will be either 32-bit or 64-bit here depending on + // the value. + // + // Calling this method if the value doesn't contain either an int32_t or an + // int64_t will return std::nullopt. + std::optional TryGetLongValue() const { + if (std::holds_alternative(*this)) { + return std::get(*this); + } + if (std::holds_alternative(*this)) { + return std::get(*this); + } + return std::nullopt; + } + // The C++ Standard Library implementations can get into issues with recursive // constraint satisfaction when (among other things) objects of this type (which // is an `std::variant` subclass) are put into containers like `std::vector`. diff --git a/flutter/shell/platform/common/windowing.h b/flutter/shell/platform/common/windowing.h index 5c37df32..beb2ca45 100644 --- a/flutter/shell/platform/common/windowing.h +++ b/flutter/shell/platform/common/windowing.h @@ -8,11 +8,12 @@ namespace flutter { // Types of windows. -// The value must match value from WindowType in the Dart code -// in packages/flutter/lib/src/widgets/window.dart enum class WindowArchetype { // Regular top-level window. kRegular, + + // Dialog window. + kDialog, }; } // namespace flutter diff --git a/flutter/shell/platform/embedder/embedder.h b/flutter/shell/platform/embedder/embedder.h index 9249f082..1fd58e5b 100644 --- a/flutter/shell/platform/embedder/embedder.h +++ b/flutter/shell/platform/embedder/embedder.h @@ -352,6 +352,8 @@ typedef struct { bool is_slider; /// Whether the semantics node represents a keyboard key. bool is_keyboard_key; + /// Whether to block a11y focus for the semantics node. + bool is_accessibility_focus_blocked; } FlutterSemanticsFlags; typedef enum { @@ -1742,6 +1744,11 @@ typedef struct { /// heading; higher values (1, 2, …) indicate the heading rank, with lower /// numbers being higher-level headings. int32_t heading_level; + /// An identifier for the semantics node in native accessibility hierarchy. + /// This value should not be exposed to the users of the app. + /// This is usually used for UI testing with tools that work by querying the + /// native accessibility, like UI Automator, XCUITest, or Appium. + const char* identifier; } FlutterSemanticsNode2; /// `FlutterSemanticsCustomAction` ID used as a sentinel to signal the end of a diff --git a/flutter/third_party/accessibility/ax/ax_active_popup.h b/flutter/third_party/accessibility/ax/ax_active_popup.h index 94f15c66..39b8beda 100644 --- a/flutter/third_party/accessibility/ax/ax_active_popup.h +++ b/flutter/third_party/accessibility/ax/ax_active_popup.h @@ -5,7 +5,6 @@ #ifndef UI_ACCESSIBILITY_AX_ACTIVE_POPUP_H_ #define UI_ACCESSIBILITY_AX_ACTIVE_POPUP_H_ -#include #include #include "ax/ax_export.h" diff --git a/flutter/third_party/accessibility/ax/ax_constants.h b/flutter/third_party/accessibility/ax/ax_constants.h index e9e7388b..db93292e 100644 --- a/flutter/third_party/accessibility/ax/ax_constants.h +++ b/flutter/third_party/accessibility/ax/ax_constants.h @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef UI_ACCESSIBILITY_AX_CONSTANTS_H_ +#define UI_ACCESSIBILITY_AX_CONSTANTS_H_ + #include namespace ax { @@ -19,3 +22,5 @@ const int32_t kUnknownAriaColumnOrRowCount = -1; } // namespace mojom } // namespace ax + +#endif // UI_ACCESSIBILITY_AX_CONSTANTS_H_ diff --git a/flutter/third_party/accessibility/ax/ax_enum_util.cc b/flutter/third_party/accessibility/ax/ax_enum_util.cc index 120e0615..34d34c5a 100644 --- a/flutter/third_party/accessibility/ax/ax_enum_util.cc +++ b/flutter/third_party/accessibility/ax/ax_enum_util.cc @@ -1433,6 +1433,8 @@ const char* ToString(ax::mojom::StringAttribute string_attribute) { return "fontFamily"; case ax::mojom::StringAttribute::kHtmlTag: return "htmlTag"; + case ax::mojom::StringAttribute::kIdentifier: + return "identifier"; case ax::mojom::StringAttribute::kImageAnnotation: return "imageAnnotation"; case ax::mojom::StringAttribute::kImageDataUrl: @@ -1493,6 +1495,8 @@ ax::mojom::StringAttribute ParseStringAttribute(const char* string_attribute) { return ax::mojom::StringAttribute::kFontFamily; if (0 == strcmp(string_attribute, "htmlTag")) return ax::mojom::StringAttribute::kHtmlTag; + if (0 == strcmp(string_attribute, "identifier")) + return ax::mojom::StringAttribute::kIdentifier; if (0 == strcmp(string_attribute, "imageAnnotation")) return ax::mojom::StringAttribute::kImageAnnotation; if (0 == strcmp(string_attribute, "imageDataUrl")) diff --git a/flutter/third_party/accessibility/ax/ax_enums.h b/flutter/third_party/accessibility/ax/ax_enums.h index 1a444cde..70f2e379 100644 --- a/flutter/third_party/accessibility/ax/ax_enums.h +++ b/flutter/third_party/accessibility/ax/ax_enums.h @@ -533,6 +533,7 @@ enum class StringAttribute { // Only present when different from parent. kFontFamily, kHtmlTag, + kIdentifier, // Stores an automatic image annotation if one is available. Only valid on // ax::mojom::Role::kImage. See kImageAnnotationStatus, too. kImageAnnotation, diff --git a/flutter/third_party/accessibility/ax/ax_event_generator.h b/flutter/third_party/accessibility/ax/ax_event_generator.h index 63d43525..688cffcd 100644 --- a/flutter/third_party/accessibility/ax/ax_event_generator.h +++ b/flutter/third_party/accessibility/ax/ax_event_generator.h @@ -125,14 +125,9 @@ class AX_EXPORT AXEventGenerator : public AXTreeObserver { const EventParams& event_params; }; - class AX_EXPORT Iterator { + class AX_EXPORT Iterator + : public std::iterator { public: - using iterator_category = std::input_iterator_tag; - using value_type = TargetedEvent; - using difference_type = std::ptrdiff_t; - using pointer = TargetedEvent*; - using reference = TargetedEvent&; - Iterator( const std::map>& map, const std::map>::const_iterator& head); diff --git a/flutter/third_party/accessibility/ax/ax_event_intent.cc b/flutter/third_party/accessibility/ax/ax_event_intent.cc index 6c571482..56b447a1 100644 --- a/flutter/third_party/accessibility/ax/ax_event_intent.cc +++ b/flutter/third_party/accessibility/ax/ax_event_intent.cc @@ -28,10 +28,6 @@ bool operator==(const AXEventIntent& a, const AXEventIntent& b) { a.move_direction == b.move_direction; } -bool operator!=(const AXEventIntent& a, const AXEventIntent& b) { - return !(a == b); -} - std::string AXEventIntent::ToString() const { return std::string("AXEventIntent(") + ui::ToString(command) + ',' + ui::ToString(text_boundary) + ',' + ui::ToString(move_direction) + ')'; diff --git a/flutter/third_party/accessibility/ax/ax_event_intent.h b/flutter/third_party/accessibility/ax/ax_event_intent.h index 6ecfec10..73916cd7 100644 --- a/flutter/third_party/accessibility/ax/ax_event_intent.h +++ b/flutter/third_party/accessibility/ax/ax_event_intent.h @@ -27,8 +27,6 @@ struct AX_BASE_EXPORT AXEventIntent final { friend AX_BASE_EXPORT bool operator==(const AXEventIntent& a, const AXEventIntent& b); - friend AX_BASE_EXPORT bool operator!=(const AXEventIntent& a, - const AXEventIntent& b); ax::mojom::Command command = ax::mojom::Command::kType; // TODO(nektar): Split TextBoundary into TextUnit and TextBoundary. diff --git a/flutter/third_party/accessibility/ax/ax_node_data.cc b/flutter/third_party/accessibility/ax/ax_node_data.cc index f13be3d2..48cbc7ce 100644 --- a/flutter/third_party/accessibility/ax/ax_node_data.cc +++ b/flutter/third_party/accessibility/ax/ax_node_data.cc @@ -1465,6 +1465,9 @@ std::string AXNodeData::ToString() const { case ax::mojom::StringAttribute::kHtmlTag: result += " html_tag=" + value; break; + case ax::mojom::StringAttribute::kIdentifier: + result += " identifer=" + value; + break; case ax::mojom::StringAttribute::kImageAnnotation: result += " image_annotation=" + value; break; diff --git a/flutter/third_party/accessibility/ax/platform/ax_platform_node_delegate_base.cc b/flutter/third_party/accessibility/ax/platform/ax_platform_node_delegate_base.cc index 501c7509..52288f6f 100644 --- a/flutter/third_party/accessibility/ax/platform/ax_platform_node_delegate_base.cc +++ b/flutter/third_party/accessibility/ax/platform/ax_platform_node_delegate_base.cc @@ -12,6 +12,7 @@ #include "ax/ax_role_properties.h" #include "ax/ax_tree_data.h" #include "base/no_destructor.h" +#include "base/string_utils.h" #include "ax_platform_node.h" #include "ax_platform_node_base.h" @@ -629,7 +630,7 @@ std::set AXPlatformNodeDelegateBase::GetReverseRelations( } std::u16string AXPlatformNodeDelegateBase::GetAuthorUniqueId() const { - return std::u16string(); + return base::UTF8ToUTF16(GetData().GetStringAttribute(ax::mojom::StringAttribute::kIdentifier)); } const AXUniqueId& AXPlatformNodeDelegateBase::GetUniqueId() const { diff --git a/flutter/third_party/accessibility/ax/platform/ax_platform_node_mac.h b/flutter/third_party/accessibility/ax/platform/ax_platform_node_mac.h index 1de7f4bc..6719056e 100644 --- a/flutter/third_party/accessibility/ax/platform/ax_platform_node_mac.h +++ b/flutter/third_party/accessibility/ax/platform/ax_platform_node_mac.h @@ -8,7 +8,6 @@ #import #include "base/macros.h" -#include "base/platform/darwin/scoped_nsobject.h" #include "ax/ax_export.h" @@ -39,7 +38,7 @@ class AXPlatformNodeMac : public AXPlatformNodeBase { private: ~AXPlatformNodeMac() override; - base::scoped_nsobject native_node_; + AXPlatformNodeCocoa* native_node_; BASE_DISALLOW_COPY_AND_ASSIGN(AXPlatformNodeMac); }; diff --git a/flutter/third_party/accessibility/ax/platform/ax_platform_node_mac.mm b/flutter/third_party/accessibility/ax/platform/ax_platform_node_mac.mm index 572b2ca7..e16b08ac 100644 --- a/flutter/third_party/accessibility/ax/platform/ax_platform_node_mac.mm +++ b/flutter/third_party/accessibility/ax/platform/ax_platform_node_mac.mm @@ -28,8 +28,8 @@ using ActionList = std::vector>; struct AnnouncementSpec { - base::scoped_nsobject announcement; - base::scoped_nsobject window; + NSString* announcement; + NSWindow* window; bool is_polite; }; @@ -434,8 +434,8 @@ - (NSString*)getName { return nullptr; auto announcement = std::make_unique(); - announcement->announcement = base::scoped_nsobject([announcementText retain]); - announcement->window = base::scoped_nsobject([[self AXWindowInternal] retain]); + announcement->announcement = announcementText; + announcement->window = [self AXWindowInternal]; announcement->is_polite = liveStatus != "assertive"; return announcement; } @@ -498,7 +498,7 @@ - (NSArray*)accessibilityActionNames { if (!_node) return @[]; - base::scoped_nsobject axActions([[NSMutableArray alloc] init]); + NSMutableArray* axActions = [[NSMutableArray alloc] init]; const ui::AXNodeData& data = _node->GetData(); const ActionList& action_list = GetActionList(); @@ -514,7 +514,7 @@ - (NSArray*)accessibilityActionNames { if (AlsoUseShowMenuActionForDefaultAction(data)) [axActions addObject:NSAccessibilityShowMenuAction]; - return axActions.autorelease(); + return axActions; } - (void)accessibilityPerformAction:(NSString*)action { @@ -834,8 +834,7 @@ - (BOOL)isAccessibilitySelectorAllowed:(SEL)selector { // accessibility clients from trying to set the selection range, which won't // work because of 692362. if (selector == @selector(setAccessibilitySelectedText:) || - selector == @selector(setAccessibilitySelectedTextRange:) || - selector == @selector(setAccessibilitySelectedTextMarkerRange:)) { + selector == @selector(setAccessibilitySelectedTextRange:)) { return restriction != ax::mojom::Restriction::kReadOnly; } @@ -973,9 +972,7 @@ - (NSAttributedString*)accessibilityAttributedStringForRange:(NSRange)range { if (!_node) return nil; // TODO(https://crbug.com/958811): Implement this for real. - base::scoped_nsobject attributedString( - [[NSAttributedString alloc] initWithString:[self accessibilityStringForRange:range]]); - return attributedString.autorelease(); + return [[NSAttributedString alloc] initWithString:[self accessibilityStringForRange:range]]; } - (NSData*)accessibilityRTFForRange:(NSRange)range { @@ -1085,8 +1082,8 @@ - (BOOL)isAccessibilityFocused { gfx::NativeViewAccessible AXPlatformNodeMac::GetNativeViewAccessible() { if (!native_node_) - native_node_.reset([[AXPlatformNodeCocoa alloc] initWithNode:this]); - return native_node_.get(); + native_node_ = [[AXPlatformNodeCocoa alloc] initWithNode:this]; + return native_node_; } void AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event event_type) {