@@ -56,6 +56,36 @@ void AccessibilityObjectDidLoseFocus(int32_t id) override {}
5656 UIView* view_;
5757 UIWindow* window_;
5858};
59+
60+ class MockAccessibilityBridgeNoWindow : public AccessibilityBridgeIos {
61+ public:
62+ MockAccessibilityBridgeNoWindow () : observations({}) {
63+ view_ = [[UIView alloc ] initWithFrame: kScreenSize ];
64+ }
65+ bool isVoiceOverRunning () const override { return isVoiceOverRunningValue; }
66+ UIView* view () const override { return view_; }
67+ UIView<UITextInput>* textInputView () override { return nil ; }
68+ void DispatchSemanticsAction (int32_t id , SemanticsAction action) override {
69+ SemanticsActionObservation observation (id , action);
70+ observations.push_back (observation);
71+ }
72+ void DispatchSemanticsAction (int32_t id ,
73+ SemanticsAction action,
74+ fml::MallocMapping args) override {
75+ SemanticsActionObservation observation (id , action);
76+ observations.push_back (observation);
77+ }
78+ void AccessibilityObjectDidBecomeFocused (int32_t id ) override {}
79+ void AccessibilityObjectDidLoseFocus (int32_t id ) override {}
80+ std::shared_ptr<FlutterPlatformViewsController> GetPlatformViewsController () const override {
81+ return nil ;
82+ }
83+ std::vector<SemanticsActionObservation> observations;
84+ bool isVoiceOverRunningValue;
85+
86+ private:
87+ UIView* view_;
88+ };
5989} // namespace
6090} // namespace flutter
6191
@@ -208,6 +238,46 @@ - (void)testVerticalFlutterScrollableSemanticsObject {
208238 CGPointMake (0 , scrollPosition * effectivelyScale)));
209239}
210240
241+ - (void )testVerticalFlutterScrollableSemanticsObjectNoWindow {
242+ fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory (
243+ new flutter::MockAccessibilityBridgeNoWindow ());
244+ fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr ();
245+
246+ float transformScale = 0 .5f ;
247+ float screenScale =
248+ [UIScreen mainScreen ].scale ; // Flutter view without window uses [UIScreen mainScreen];
249+ float effectivelyScale = transformScale / screenScale;
250+ float x = 10 ;
251+ float y = 10 ;
252+ float w = 100 ;
253+ float h = 200 ;
254+ float scrollExtentMax = 500.0 ;
255+ float scrollPosition = 150.0 ;
256+
257+ flutter::SemanticsNode node;
258+ node.flags = static_cast <int32_t >(flutter::SemanticsFlags::kHasImplicitScrolling );
259+ node.actions = flutter::kVerticalScrollSemanticsActions ;
260+ node.rect = SkRect::MakeXYWH (x, y, w, h);
261+ node.scrollExtentMax = scrollExtentMax;
262+ node.scrollPosition = scrollPosition;
263+ node.transform = {
264+ transformScale, 0 , 0 , 0 , 0 , transformScale, 0 , 0 , 0 , 0 , transformScale, 0 , 0 , 0 , 0 , 1.0 };
265+ FlutterSemanticsObject* delegate = [[FlutterSemanticsObject alloc ] initWithBridge: bridge uid: 0 ];
266+ FlutterScrollableSemanticsObject* scrollable =
267+ [[FlutterScrollableSemanticsObject alloc ] initWithSemanticsObject: delegate];
268+ SemanticsObject* scrollable_object = static_cast <SemanticsObject*>(scrollable);
269+ [scrollable_object setSemanticsNode: &node];
270+ [scrollable_object accessibilityBridgeDidFinishUpdate ];
271+ XCTAssertTrue (
272+ CGRectEqualToRect (scrollable.frame , CGRectMake (x * effectivelyScale, y * effectivelyScale,
273+ w * effectivelyScale, h * effectivelyScale)));
274+ XCTAssertTrue (CGSizeEqualToSize (
275+ scrollable.contentSize ,
276+ CGSizeMake (w * effectivelyScale, (h + scrollExtentMax) * effectivelyScale)));
277+ XCTAssertTrue (CGPointEqualToPoint (scrollable.contentOffset ,
278+ CGPointMake (0 , scrollPosition * effectivelyScale)));
279+ }
280+
211281- (void )testHorizontalFlutterScrollableSemanticsObject {
212282 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory (
213283 new flutter::MockAccessibilityBridge ());
0 commit comments