7 #include <UIAutomation.h>
15 #include "flutter/fml/synchronization/waitable_event.h"
17 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
22 #include "flutter/shell/platform/windows/testing/egl/mock_context.h"
23 #include "flutter/shell/platform/windows/testing/egl/mock_manager.h"
24 #include "flutter/shell/platform/windows/testing/egl/mock_window_surface.h"
25 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
26 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
27 #include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
28 #include "flutter/shell/platform/windows/testing/test_keyboard.h"
29 #include "flutter/shell/platform/windows/testing/view_modifier.h"
31 #include "gmock/gmock.h"
32 #include "gtest/gtest.h"
38 using ::testing::InSequence;
39 using ::testing::NiceMock;
40 using ::testing::Return;
51 struct TestResponseHandle {
56 static bool test_response =
false;
58 constexpr uint64_t kKeyEventFromChannel = 0x11;
59 constexpr uint64_t kKeyEventFromEmbedder = 0x22;
60 static std::vector<int> key_event_logs;
62 std::unique_ptr<std::vector<uint8_t>> keyHandlingResponse(
bool handled) {
63 rapidjson::Document document;
64 auto& allocator = document.GetAllocator();
66 document.AddMember(
"handled", test_response, allocator);
72 FlutterProjectBundle GetTestProject() {
74 properties.
assets_path = L
"C:\\foo\\flutter_assets";
78 return FlutterProjectBundle{properties};
84 std::unique_ptr<FlutterWindowsEngine> GetTestEngine(
85 std::shared_ptr<WindowsProcTable> windows_proc_table =
nullptr) {
86 auto engine = std::make_unique<FlutterWindowsEngine>(
87 GetTestProject(), std::move(windows_proc_table));
89 EngineModifier modifier(engine.get());
90 modifier.SetEGLManager(
nullptr);
92 auto key_response_controller = std::make_shared<MockKeyResponseController>();
93 key_response_controller->SetChannelResponse(
94 [](MockKeyResponseController::ResponseCallback
callback) {
95 key_event_logs.push_back(kKeyEventFromChannel);
98 key_response_controller->SetEmbedderResponse(
99 [](
const FlutterKeyEvent* event,
100 MockKeyResponseController::ResponseCallback
callback) {
101 key_event_logs.push_back(kKeyEventFromEmbedder);
104 modifier.embedder_api().NotifyDisplayUpdate =
105 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
106 ([engine_instance = engine.get()](
107 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
108 const FlutterEngineDisplaysUpdateType update_type,
109 const FlutterEngineDisplay* embedder_displays,
110 size_t display_count) {
return kSuccess; }));
112 MockEmbedderApiForKeyboard(modifier, key_response_controller);
118 class MockFlutterWindowsEngine :
public FlutterWindowsEngine {
120 explicit MockFlutterWindowsEngine(
121 std::shared_ptr<WindowsProcTable> windows_proc_table =
nullptr)
122 : FlutterWindowsEngine(GetTestProject(), std::move(windows_proc_table)) {}
124 MOCK_METHOD(
bool, running, (), (
const));
125 MOCK_METHOD(
bool, Stop, (), ());
127 MOCK_METHOD(
bool, PostRasterThreadTask, (fml::closure), (
const));
130 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsEngine);
137 TEST(FlutterWindowsViewTest, SubMenuExpandedState) {
138 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
139 EngineModifier modifier(engine.get());
140 modifier.embedder_api().UpdateSemanticsEnabled =
145 auto window_binding_handler =
146 std::make_unique<NiceMock<MockWindowBindingHandler>>();
147 std::unique_ptr<FlutterWindowsView> view =
148 engine->CreateView(std::move(window_binding_handler),
149 false, BoxConstraints());
152 view->OnUpdateSemanticsEnabled(
true);
154 auto bridge = view->accessibility_bridge().lock();
157 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
162 root.increased_value =
"";
163 root.decreased_value =
"";
164 root.child_count = 0;
165 root.custom_accessibility_actions_count = 0;
166 auto flags = FlutterSemanticsFlags{
167 .is_expanded = FlutterTristate::kFlutterTristateTrue,
169 root.flags2 = &flags;
171 bridge->AddFlutterSemanticsNodeUpdate(root);
173 bridge->CommitUpdates();
176 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
177 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kExpanded));
180 IAccessible* native_view = root_node->GetNativeViewAccessible();
181 ASSERT_TRUE(native_view !=
nullptr);
184 VARIANT varchild = {};
188 varchild.lVal = CHILDID_SELF;
189 VARIANT native_state = {};
190 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
191 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_EXPANDED);
194 IRawElementProviderSimple* uia_node;
195 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
196 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
197 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
198 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Expanded);
200 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
201 UIA_AriaPropertiesPropertyId, &native_state)));
202 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=true"),
nullptr);
206 auto updated_flags = FlutterSemanticsFlags{
207 .is_expanded = FlutterTristate::kFlutterTristateFalse,
209 root.flags2 = &updated_flags;
211 bridge->AddFlutterSemanticsNodeUpdate(root);
212 bridge->CommitUpdates();
215 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
216 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kCollapsed));
219 IAccessible* native_view = root_node->GetNativeViewAccessible();
220 ASSERT_TRUE(native_view !=
nullptr);
223 VARIANT varchild = {};
227 varchild.lVal = CHILDID_SELF;
228 VARIANT native_state = {};
229 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
230 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_COLLAPSED);
233 IRawElementProviderSimple* uia_node;
234 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
235 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
236 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
237 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Collapsed);
239 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
240 UIA_AriaPropertiesPropertyId, &native_state)));
241 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=false"),
nullptr);
247 TEST(FlutterWindowsViewTest, Shutdown) {
248 auto engine = std::make_unique<MockFlutterWindowsEngine>();
249 auto window_binding_handler =
250 std::make_unique<NiceMock<MockWindowBindingHandler>>();
251 auto egl_manager = std::make_unique<egl::MockManager>();
252 auto surface = std::make_unique<egl::MockWindowSurface>();
253 egl::MockContext render_context;
255 auto engine_ptr = engine.get();
256 auto surface_ptr = surface.get();
257 auto egl_manager_ptr = egl_manager.get();
259 EngineModifier modifier{engine.get()};
260 modifier.SetEGLManager(std::move(egl_manager));
263 std::unique_ptr<FlutterWindowsView> view;
267 EXPECT_CALL(*egl_manager_ptr, CreateWindowSurface)
268 .WillOnce(Return(std::move(surface)));
269 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
false));
270 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
271 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
272 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
273 EXPECT_CALL(*egl_manager_ptr, render_context)
274 .WillOnce(Return(&render_context));
275 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
277 view = engine->CreateView(std::move(window_binding_handler),
false,
283 auto view_id = view->view_id();
286 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
true));
287 EXPECT_CALL(*engine_ptr, RemoveView(view_id)).Times(1);
288 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
true));
289 EXPECT_CALL(*engine_ptr, PostRasterThreadTask)
290 .WillOnce([](fml::closure
callback) {
294 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
298 TEST(FlutterWindowsViewTest, KeySequence) {
299 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
301 test_response =
false;
303 std::unique_ptr<FlutterWindowsView> view =
304 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
305 false, BoxConstraints());
308 [](
bool handled) {});
310 EXPECT_EQ(key_event_logs.size(), 2);
311 EXPECT_EQ(key_event_logs[0], kKeyEventFromEmbedder);
312 EXPECT_EQ(key_event_logs[1], kKeyEventFromChannel);
314 key_event_logs.clear();
317 TEST(FlutterWindowsViewTest, KeyEventCallback) {
318 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
320 std::unique_ptr<FlutterWindowsView> view =
321 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
322 false, BoxConstraints());
326 MOCK_METHOD(
void, Call, ());
329 NiceMock<MockCallback> callback_with_valid_view;
330 NiceMock<MockCallback> callback_with_invalid_view;
332 auto trigger_key_event = [&](NiceMock<MockCallback>&
callback) {
337 EXPECT_CALL(callback_with_valid_view, Call()).Times(1);
338 EXPECT_CALL(callback_with_invalid_view, Call()).Times(0);
340 trigger_key_event(callback_with_valid_view);
341 engine->RemoveView(view->view_id());
342 trigger_key_event(callback_with_invalid_view);
344 key_event_logs.clear();
347 TEST(FlutterWindowsViewTest, EnableSemantics) {
348 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
349 EngineModifier modifier(engine.get());
351 bool semantics_enabled =
false;
352 modifier.embedder_api().UpdateSemanticsEnabled = MOCK_ENGINE_PROC(
353 UpdateSemanticsEnabled,
354 [&semantics_enabled](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
356 semantics_enabled = enabled;
360 auto window_binding_handler =
361 std::make_unique<NiceMock<MockWindowBindingHandler>>();
362 std::unique_ptr<FlutterWindowsView> view =
363 engine->CreateView(std::move(window_binding_handler),
364 false, BoxConstraints());
366 view->OnUpdateSemanticsEnabled(
true);
367 EXPECT_TRUE(semantics_enabled);
370 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdate) {
371 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
372 EngineModifier modifier(engine.get());
373 modifier.embedder_api().UpdateSemanticsEnabled =
378 auto window_binding_handler =
379 std::make_unique<NiceMock<MockWindowBindingHandler>>();
380 std::unique_ptr<FlutterWindowsView> view =
381 engine->CreateView(std::move(window_binding_handler),
382 false, BoxConstraints());
385 view->OnUpdateSemanticsEnabled(
true);
387 auto bridge = view->accessibility_bridge().lock();
391 FlutterSemanticsNode2 node{
sizeof(FlutterSemanticsNode2), 0};
393 node.value =
"value";
394 node.platform_view_id = -1;
395 auto flags = FlutterSemanticsFlags{};
396 node.flags2 = &flags;
397 bridge->AddFlutterSemanticsNodeUpdate(node);
398 bridge->CommitUpdates();
401 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
406 IAccessible* native_view =
node_delegate->GetNativeViewAccessible();
407 ASSERT_TRUE(native_view !=
nullptr);
412 varchild.lVal = CHILDID_SELF;
415 BSTR bname =
nullptr;
416 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
417 std::string name(_com_util::ConvertBSTRToString(bname));
418 EXPECT_EQ(name,
"name");
421 BSTR bvalue =
nullptr;
422 ASSERT_EQ(native_view->get_accValue(varchild, &bvalue), S_OK);
423 std::string value(_com_util::ConvertBSTRToString(bvalue));
424 EXPECT_EQ(value,
"value");
429 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
430 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
433 IRawElementProviderSimple* uia_view;
434 native_view->QueryInterface(IID_PPV_ARGS(&uia_view));
435 ASSERT_TRUE(uia_view !=
nullptr);
439 ASSERT_EQ(uia_view->GetPropertyValue(UIA_NamePropertyId, &varname), S_OK);
440 EXPECT_EQ(varname.vt, VT_BSTR);
441 name = _com_util::ConvertBSTRToString(varname.bstrVal);
442 EXPECT_EQ(name,
"name");
446 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue),
448 EXPECT_EQ(varvalue.vt, VT_BSTR);
449 value = _com_util::ConvertBSTRToString(varvalue.bstrVal);
450 EXPECT_EQ(value,
"value");
454 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
456 EXPECT_EQ(varrole.vt, VT_I4);
457 EXPECT_EQ(varrole.lVal, UIA_TextControlTypeId);
472 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdateWithChildren) {
473 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
474 EngineModifier modifier(engine.get());
475 modifier.embedder_api().UpdateSemanticsEnabled =
480 std::unique_ptr<FlutterWindowsView> view =
481 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
482 false, BoxConstraints());
485 view->OnUpdateSemanticsEnabled(
true);
487 auto bridge = view->accessibility_bridge().lock();
491 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
492 std::vector<int32_t> node0_children{1, 2};
493 node0.child_count = node0_children.size();
494 node0.children_in_traversal_order = node0_children.data();
495 node0.children_in_hit_test_order = node0_children.data();
496 auto empty_flags = FlutterSemanticsFlags{};
497 node0.flags2 = &empty_flags;
499 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
500 node1.label =
"prefecture";
501 node1.value =
"Kyoto";
502 node1.flags2 = &empty_flags;
503 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
504 std::vector<int32_t> node2_children{3};
505 node2.child_count = node2_children.size();
506 node2.children_in_traversal_order = node2_children.data();
507 node2.children_in_hit_test_order = node2_children.data();
508 node2.flags2 = &empty_flags;
509 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
510 node3.label =
"city";
512 node3.flags2 = &empty_flags;
514 bridge->AddFlutterSemanticsNodeUpdate(node0);
515 bridge->AddFlutterSemanticsNodeUpdate(node1);
516 bridge->AddFlutterSemanticsNodeUpdate(node2);
517 bridge->AddFlutterSemanticsNodeUpdate(node3);
518 bridge->CommitUpdates();
521 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
526 IAccessible* node0_accessible =
node_delegate->GetNativeViewAccessible();
527 ASSERT_TRUE(node0_accessible !=
nullptr);
532 varchild.lVal = CHILDID_SELF;
537 ASSERT_EQ(node0_accessible->get_accRole(varchild, &varrole), S_OK);
538 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
541 long node0_child_count = 0;
542 ASSERT_EQ(node0_accessible->get_accChildCount(&node0_child_count), S_OK);
543 EXPECT_EQ(node0_child_count, 2);
548 IDispatch* node1_dispatch =
nullptr;
549 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node1_dispatch), S_OK);
550 ASSERT_TRUE(node1_dispatch !=
nullptr);
551 IAccessible* node1_accessible =
nullptr;
552 ASSERT_EQ(node1_dispatch->QueryInterface(
553 IID_IAccessible,
reinterpret_cast<void**
>(&node1_accessible)),
555 ASSERT_TRUE(node1_accessible !=
nullptr);
558 varchild.lVal = CHILDID_SELF;
559 BSTR bname =
nullptr;
560 ASSERT_EQ(node1_accessible->get_accName(varchild, &bname), S_OK);
561 std::string name(_com_util::ConvertBSTRToString(bname));
562 EXPECT_EQ(name,
"prefecture");
565 BSTR bvalue =
nullptr;
566 ASSERT_EQ(node1_accessible->get_accValue(varchild, &bvalue), S_OK);
567 std::string value(_com_util::ConvertBSTRToString(bvalue));
568 EXPECT_EQ(value,
"Kyoto");
573 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
574 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
577 IDispatch* parent_dispatch;
578 node1_accessible->get_accParent(&parent_dispatch);
579 IAccessible* parent_accessible;
581 parent_dispatch->QueryInterface(
582 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
584 EXPECT_EQ(parent_accessible, node0_accessible);
589 IDispatch* node2_dispatch =
nullptr;
590 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
591 ASSERT_TRUE(node2_dispatch !=
nullptr);
592 IAccessible* node2_accessible =
nullptr;
593 ASSERT_EQ(node2_dispatch->QueryInterface(
594 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
596 ASSERT_TRUE(node2_accessible !=
nullptr);
600 long node2_child_count = 0;
601 ASSERT_EQ(node2_accessible->get_accChildCount(&node2_child_count), S_OK);
602 EXPECT_EQ(node2_child_count, 1);
605 varchild.lVal = CHILDID_SELF;
608 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
609 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
612 IDispatch* parent_dispatch;
613 node2_accessible->get_accParent(&parent_dispatch);
614 IAccessible* parent_accessible;
616 parent_dispatch->QueryInterface(
617 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
619 EXPECT_EQ(parent_accessible, node0_accessible);
625 IDispatch* node3_dispatch =
nullptr;
626 ASSERT_EQ(node2_accessible->get_accChild(varchild, &node3_dispatch), S_OK);
627 ASSERT_TRUE(node3_dispatch !=
nullptr);
628 IAccessible* node3_accessible =
nullptr;
629 ASSERT_EQ(node3_dispatch->QueryInterface(
630 IID_IAccessible,
reinterpret_cast<void**
>(&node3_accessible)),
632 ASSERT_TRUE(node3_accessible !=
nullptr);
635 varchild.lVal = CHILDID_SELF;
636 BSTR bname =
nullptr;
637 ASSERT_EQ(node3_accessible->get_accName(varchild, &bname), S_OK);
638 std::string name(_com_util::ConvertBSTRToString(bname));
639 EXPECT_EQ(name,
"city");
642 BSTR bvalue =
nullptr;
643 ASSERT_EQ(node3_accessible->get_accValue(varchild, &bvalue), S_OK);
644 std::string value(_com_util::ConvertBSTRToString(bvalue));
645 EXPECT_EQ(value,
"Uji");
650 ASSERT_EQ(node3_accessible->get_accRole(varchild, &varrole), S_OK);
651 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
654 IDispatch* parent_dispatch;
655 node3_accessible->get_accParent(&parent_dispatch);
656 IAccessible* parent_accessible;
658 parent_dispatch->QueryInterface(
659 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
661 EXPECT_EQ(parent_accessible, node2_accessible);
674 TEST(FlutterWindowsViewTest, NonZeroSemanticsRoot) {
675 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
676 EngineModifier modifier(engine.get());
677 modifier.embedder_api().UpdateSemanticsEnabled =
682 std::unique_ptr<FlutterWindowsView> view =
683 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
684 false, BoxConstraints());
687 view->OnUpdateSemanticsEnabled(
true);
689 auto bridge = view->accessibility_bridge().lock();
693 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
694 std::vector<int32_t> node1_children{2};
695 node1.child_count = node1_children.size();
696 node1.children_in_traversal_order = node1_children.data();
697 node1.children_in_hit_test_order = node1_children.data();
698 auto empty_flags = FlutterSemanticsFlags{};
699 node1.flags2 = &empty_flags;
701 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
702 node2.label =
"prefecture";
703 node2.value =
"Kyoto";
704 node2.flags2 = &empty_flags;
705 bridge->AddFlutterSemanticsNodeUpdate(node1);
706 bridge->AddFlutterSemanticsNodeUpdate(node2);
707 bridge->CommitUpdates();
710 auto root_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
711 ASSERT_TRUE(root_delegate);
712 EXPECT_EQ(root_delegate->GetChildCount(), 1);
715 auto child_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
716 ASSERT_TRUE(child_delegate);
717 EXPECT_EQ(child_delegate->GetChildCount(), 0);
720 auto fake_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
721 ASSERT_FALSE(fake_delegate);
724 IAccessible* node1_accessible = root_delegate->GetNativeViewAccessible();
725 ASSERT_TRUE(node1_accessible !=
nullptr);
730 varchild.lVal = CHILDID_SELF;
735 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
736 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
739 long node1_child_count = 0;
740 ASSERT_EQ(node1_accessible->get_accChildCount(&node1_child_count), S_OK);
741 EXPECT_EQ(node1_child_count, 1);
746 IDispatch* node2_dispatch =
nullptr;
747 ASSERT_EQ(node1_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
748 ASSERT_TRUE(node2_dispatch !=
nullptr);
749 IAccessible* node2_accessible =
nullptr;
750 ASSERT_EQ(node2_dispatch->QueryInterface(
751 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
753 ASSERT_TRUE(node2_accessible !=
nullptr);
756 varchild.lVal = CHILDID_SELF;
757 BSTR bname =
nullptr;
758 ASSERT_EQ(node2_accessible->get_accName(varchild, &bname), S_OK);
759 std::string name(_com_util::ConvertBSTRToString(bname));
760 EXPECT_EQ(name,
"prefecture");
763 BSTR bvalue =
nullptr;
764 ASSERT_EQ(node2_accessible->get_accValue(varchild, &bvalue), S_OK);
765 std::string value(_com_util::ConvertBSTRToString(bvalue));
766 EXPECT_EQ(value,
"Kyoto");
771 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
772 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
775 IDispatch* parent_dispatch;
776 node2_accessible->get_accParent(&parent_dispatch);
777 IAccessible* parent_accessible;
779 parent_dispatch->QueryInterface(
780 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
782 EXPECT_EQ(parent_accessible, node1_accessible);
803 TEST(FlutterWindowsViewTest, AccessibilityHitTesting) {
804 constexpr FlutterTransformation kIdentityTransform = {1, 0, 0,
808 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
809 EngineModifier modifier(engine.get());
810 modifier.embedder_api().UpdateSemanticsEnabled =
815 std::unique_ptr<FlutterWindowsView> view =
816 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
817 false, BoxConstraints());
820 view->OnUpdateSemanticsEnabled(
true);
822 auto bridge = view->accessibility_bridge().lock();
826 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
827 auto empty_flags = FlutterSemanticsFlags{};
828 std::vector<int32_t> node0_children{1, 2};
829 node0.rect = {0, 0, 500, 500};
830 node0.transform = kIdentityTransform;
831 node0.child_count = node0_children.size();
832 node0.children_in_traversal_order = node0_children.data();
833 node0.children_in_hit_test_order = node0_children.data();
834 node0.flags2 = &empty_flags;
837 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
838 node1.rect = {0, 0, 250, 500};
839 node1.transform = kIdentityTransform;
840 node1.label =
"prefecture";
841 node1.value =
"Kyoto";
842 node1.flags2 = &empty_flags;
845 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
846 std::vector<int32_t> node2_children{3};
847 node2.rect = {0, 0, 250, 500};
848 node2.transform = {1, 0, 250, 0, 1, 0, 0, 0, 1};
849 node2.child_count = node2_children.size();
850 node2.children_in_traversal_order = node2_children.data();
851 node2.children_in_hit_test_order = node2_children.data();
852 node2.flags2 = &empty_flags;
855 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
856 node3.rect = {0, 0, 250, 250};
857 node3.transform = {1, 0, 0, 0, 1, 250, 0, 0, 1};
858 node3.label =
"city";
860 node3.flags2 = &empty_flags;
862 bridge->AddFlutterSemanticsNodeUpdate(node0);
863 bridge->AddFlutterSemanticsNodeUpdate(node1);
864 bridge->AddFlutterSemanticsNodeUpdate(node2);
865 bridge->AddFlutterSemanticsNodeUpdate(node3);
866 bridge->CommitUpdates();
869 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
870 ASSERT_TRUE(node0_delegate);
871 auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
872 ASSERT_TRUE(node1_delegate);
873 auto node2_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
874 ASSERT_TRUE(node2_delegate);
875 auto node3_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(3).lock();
876 ASSERT_TRUE(node3_delegate);
879 IAccessible* node0_accessible = node0_delegate->GetNativeViewAccessible();
880 ASSERT_TRUE(node0_accessible !=
nullptr);
884 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(150, 150, &varchild)));
885 EXPECT_EQ(varchild.vt, VT_DISPATCH);
886 EXPECT_EQ(varchild.pdispVal, node1_delegate->GetNativeViewAccessible());
890 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 150, &varchild)));
891 EXPECT_EQ(varchild.vt, VT_DISPATCH);
892 EXPECT_EQ(varchild.pdispVal, node2_delegate->GetNativeViewAccessible());
896 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 450, &varchild)));
897 EXPECT_EQ(varchild.vt, VT_DISPATCH);
898 EXPECT_EQ(varchild.pdispVal, node3_delegate->GetNativeViewAccessible());
901 TEST(FlutterWindowsViewTest, WindowResizeTests) {
902 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
903 std::unique_ptr<FlutterWindowsEngine> engine =
904 GetTestEngine(windows_proc_table);
906 EngineModifier engine_modifier{engine.get()};
907 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
908 PostRenderThreadTask,
914 auto egl_manager = std::make_unique<egl::MockManager>();
915 auto surface = std::make_unique<egl::MockWindowSurface>();
916 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
917 egl::MockContext render_context;
919 auto surface_ptr = surface.get();
920 auto resized_surface_ptr = resized_surface.get();
923 EXPECT_CALL(*egl_manager, CreateWindowSurface)
924 .WillOnce(Return(std::move(surface)));
925 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
926 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
927 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
928 EXPECT_CALL(*egl_manager, render_context).WillOnce(Return(&render_context));
929 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
932 EXPECT_CALL(*surface_ptr, Destroy).WillOnce(Return(
true));
933 EXPECT_CALL(*egl_manager.get(),
934 CreateWindowSurface(_, 500, 500))
935 .WillOnce(Return(std::move((resized_surface))));
936 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
937 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
938 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
940 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
942 engine_modifier.SetEGLManager(std::move(egl_manager));
944 std::unique_ptr<FlutterWindowsView> view =
945 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
946 false, BoxConstraints());
948 fml::AutoResetWaitableEvent metrics_sent_latch;
949 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
950 SendWindowMetricsEvent,
951 ([&metrics_sent_latch](
auto engine,
952 const FlutterWindowMetricsEvent* event) {
953 metrics_sent_latch.Signal();
958 std::thread frame_thread([&metrics_sent_latch, &view]() {
959 metrics_sent_latch.Wait();
961 EXPECT_TRUE(view->OnFrameGenerated(500, 500));
962 view->OnFramePresented();
968 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
973 TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) {
974 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
975 std::unique_ptr<FlutterWindowsEngine> engine =
976 GetTestEngine(windows_proc_table);
978 EngineModifier engine_modifier{engine.get()};
979 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
980 PostRenderThreadTask,
986 auto egl_manager = std::make_unique<egl::MockManager>();
987 auto surface = std::make_unique<egl::MockWindowSurface>();
988 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
989 auto resized_surface_ptr = resized_surface.get();
991 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
992 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
994 EXPECT_CALL(*egl_manager.get(),
995 CreateWindowSurface(_, 500, 500))
996 .WillOnce(Return(std::move((resized_surface))));
997 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
998 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
999 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
1001 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
1003 fml::AutoResetWaitableEvent metrics_sent_latch;
1004 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1005 SendWindowMetricsEvent,
1006 ([&metrics_sent_latch](
auto engine,
1007 const FlutterWindowMetricsEvent* event) {
1008 metrics_sent_latch.Signal();
1012 std::unique_ptr<FlutterWindowsView> view =
1013 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1014 false, BoxConstraints());
1016 ViewModifier view_modifier{view.get()};
1017 engine_modifier.SetEGLManager(std::move(egl_manager));
1018 view_modifier.SetSurface(std::move(surface));
1021 std::thread frame_thread([&metrics_sent_latch, &view]() {
1022 metrics_sent_latch.Wait();
1025 EXPECT_TRUE(view->OnEmptyFrameGenerated());
1026 view->OnFramePresented();
1031 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
1032 frame_thread.join();
1038 TEST(FlutterWindowsViewTest, WindowResizeRace) {
1039 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1041 EngineModifier engine_modifier(engine.get());
1042 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
1043 PostRenderThreadTask,
1049 auto egl_manager = std::make_unique<egl::MockManager>();
1050 auto surface = std::make_unique<egl::MockWindowSurface>();
1052 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
1053 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
1055 std::unique_ptr<FlutterWindowsView> view =
1056 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1057 false, BoxConstraints());
1059 ViewModifier view_modifier{view.get()};
1060 engine_modifier.SetEGLManager(std::move(egl_manager));
1061 view_modifier.SetSurface(std::move(surface));
1064 ASSERT_TRUE(view->OnFrameGenerated(100, 100));
1068 EXPECT_FALSE(view->OnWindowSizeChanged(500, 500));
1073 view->OnFramePresented();
1078 TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) {
1079 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1081 EngineModifier engine_modifier(engine.get());
1082 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
1083 PostRenderThreadTask,
1089 auto egl_manager = std::make_unique<egl::MockManager>();
1090 auto surface = std::make_unique<egl::MockWindowSurface>();
1092 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1093 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
false));
1094 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
false));
1096 std::unique_ptr<FlutterWindowsView> view =
1097 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1098 false, BoxConstraints());
1100 ViewModifier view_modifier{view.get()};
1101 engine_modifier.SetEGLManager(std::move(egl_manager));
1102 view_modifier.SetSurface(std::move(surface));
1104 auto metrics_sent =
false;
1105 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1106 SendWindowMetricsEvent,
1107 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1108 metrics_sent =
true;
1112 view->OnWindowSizeChanged(500, 500);
1117 TEST(FlutterWindowsViewTest, WindowResizeWithoutSurface) {
1118 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1119 EngineModifier modifier(engine.get());
1121 auto egl_manager = std::make_unique<egl::MockManager>();
1123 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1125 std::unique_ptr<FlutterWindowsView> view =
1126 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1127 false, BoxConstraints());
1129 modifier.SetEGLManager(std::move(egl_manager));
1131 auto metrics_sent =
false;
1132 modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1133 SendWindowMetricsEvent,
1134 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1135 metrics_sent =
true;
1139 view->OnWindowSizeChanged(500, 500);
1142 TEST(FlutterWindowsViewTest, WindowRepaintTests) {
1143 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1144 EngineModifier modifier(engine.get());
1147 std::make_unique<flutter::FlutterWindow>(
1148 100, 100, engine->display_manager()),
1149 false, BoxConstraints()};
1151 bool schedule_frame_called =
false;
1152 modifier.embedder_api().ScheduleFrame =
1153 MOCK_ENGINE_PROC(ScheduleFrame, ([&schedule_frame_called](
auto engine) {
1154 schedule_frame_called =
true;
1158 view.OnWindowRepaint();
1159 EXPECT_TRUE(schedule_frame_called);
1168 TEST(FlutterWindowsViewTest, CheckboxNativeState) {
1169 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1170 EngineModifier modifier(engine.get());
1171 modifier.embedder_api().UpdateSemanticsEnabled =
1172 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1176 std::unique_ptr<FlutterWindowsView> view =
1177 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1178 false, BoxConstraints());
1181 view->OnUpdateSemanticsEnabled(
true);
1183 auto bridge = view->accessibility_bridge().lock();
1184 ASSERT_TRUE(bridge);
1186 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1188 root.label =
"root";
1191 root.increased_value =
"";
1192 root.decreased_value =
"";
1193 root.child_count = 0;
1194 root.custom_accessibility_actions_count = 0;
1195 auto flags = FlutterSemanticsFlags{
1196 .is_checked = FlutterCheckState::kFlutterCheckStateTrue,
1198 root.flags2 = &flags;
1199 bridge->AddFlutterSemanticsNodeUpdate(root);
1201 bridge->CommitUpdates();
1204 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1205 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1206 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1207 ax::mojom::CheckedState::kTrue);
1210 IAccessible* native_view = root_node->GetNativeViewAccessible();
1211 ASSERT_TRUE(native_view !=
nullptr);
1214 VARIANT varchild = {};
1215 varchild.vt = VT_I4;
1218 varchild.lVal = CHILDID_SELF;
1219 VARIANT native_state = {};
1220 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1221 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1224 IRawElementProviderSimple* uia_node;
1225 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1226 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1227 UIA_ToggleToggleStatePropertyId, &native_state)));
1228 EXPECT_EQ(native_state.lVal, ToggleState_On);
1230 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1231 UIA_AriaPropertiesPropertyId, &native_state)));
1232 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=true"),
nullptr);
1236 auto updated_flags = FlutterSemanticsFlags{
1237 .is_checked = FlutterCheckState::kFlutterCheckStateFalse,
1239 root.flags2 = &updated_flags;
1240 bridge->AddFlutterSemanticsNodeUpdate(root);
1241 bridge->CommitUpdates();
1244 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1245 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1246 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1247 ax::mojom::CheckedState::kFalse);
1250 IAccessible* native_view = root_node->GetNativeViewAccessible();
1251 ASSERT_TRUE(native_view !=
nullptr);
1254 VARIANT varchild = {};
1255 varchild.vt = VT_I4;
1258 varchild.lVal = CHILDID_SELF;
1259 VARIANT native_state = {};
1260 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1261 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1264 IRawElementProviderSimple* uia_node;
1265 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1266 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1267 UIA_ToggleToggleStatePropertyId, &native_state)));
1268 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1270 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1271 UIA_AriaPropertiesPropertyId, &native_state)));
1272 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=false"),
nullptr);
1276 auto updated_mixe_flags = FlutterSemanticsFlags{
1277 .is_checked = FlutterCheckState::kFlutterCheckStateMixed,
1279 root.flags2 = &updated_mixe_flags;
1280 bridge->AddFlutterSemanticsNodeUpdate(root);
1281 bridge->CommitUpdates();
1284 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1285 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1286 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1287 ax::mojom::CheckedState::kMixed);
1290 IAccessible* native_view = root_node->GetNativeViewAccessible();
1291 ASSERT_TRUE(native_view !=
nullptr);
1294 VARIANT varchild = {};
1295 varchild.vt = VT_I4;
1298 varchild.lVal = CHILDID_SELF;
1299 VARIANT native_state = {};
1300 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1301 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_MIXED);
1304 IRawElementProviderSimple* uia_node;
1305 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1306 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1307 UIA_ToggleToggleStatePropertyId, &native_state)));
1308 EXPECT_EQ(native_state.lVal, ToggleState_Indeterminate);
1310 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1311 UIA_AriaPropertiesPropertyId, &native_state)));
1312 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=mixed"),
nullptr);
1317 TEST(FlutterWindowsViewTest, SwitchNativeState) {
1318 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1319 EngineModifier modifier(engine.get());
1320 modifier.embedder_api().UpdateSemanticsEnabled =
1321 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1325 std::unique_ptr<FlutterWindowsView> view =
1326 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1327 false, BoxConstraints());
1330 view->OnUpdateSemanticsEnabled(
true);
1332 auto bridge = view->accessibility_bridge().lock();
1333 ASSERT_TRUE(bridge);
1335 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1337 root.label =
"root";
1340 root.increased_value =
"";
1341 root.decreased_value =
"";
1342 root.child_count = 0;
1343 root.custom_accessibility_actions_count = 0;
1345 auto flags = FlutterSemanticsFlags{
1346 .is_toggled = FlutterTristate::kFlutterTristateTrue,
1348 root.flags2 = &flags;
1349 bridge->AddFlutterSemanticsNodeUpdate(root);
1351 bridge->CommitUpdates();
1354 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1355 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1356 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1357 ax::mojom::CheckedState::kTrue);
1360 IAccessible* native_view = root_node->GetNativeViewAccessible();
1361 ASSERT_TRUE(native_view !=
nullptr);
1364 VARIANT varchild = {};
1365 varchild.vt = VT_I4;
1367 varchild.lVal = CHILDID_SELF;
1368 VARIANT varrole = {};
1371 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
1372 ASSERT_EQ(varrole.lVal, ROLE_SYSTEM_CHECKBUTTON);
1375 VARIANT native_state = {};
1376 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1377 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_PRESSED);
1378 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1381 IRawElementProviderSimple* uia_node;
1382 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1383 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
1385 EXPECT_EQ(varrole.lVal, UIA_ButtonControlTypeId);
1386 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1389 EXPECT_EQ(native_state.lVal, ToggleState_On);
1391 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1393 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=true"),
nullptr);
1397 auto updated_flags = FlutterSemanticsFlags{
1398 .is_toggled = FlutterTristate::kFlutterTristateFalse,
1400 root.flags2 = &updated_flags;
1402 bridge->AddFlutterSemanticsNodeUpdate(root);
1403 bridge->CommitUpdates();
1406 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1407 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1408 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1409 ax::mojom::CheckedState::kFalse);
1412 IAccessible* native_view = root_node->GetNativeViewAccessible();
1413 ASSERT_TRUE(native_view !=
nullptr);
1416 VARIANT varchild = {};
1417 varchild.vt = VT_I4;
1420 varchild.lVal = CHILDID_SELF;
1421 VARIANT native_state = {};
1422 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1423 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_PRESSED);
1424 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1427 IRawElementProviderSimple* uia_node;
1428 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1429 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1432 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1434 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1436 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=false"),
nullptr);
1440 TEST(FlutterWindowsViewTest, TooltipNodeData) {
1441 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1442 EngineModifier modifier(engine.get());
1443 modifier.embedder_api().UpdateSemanticsEnabled =
1444 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1448 std::unique_ptr<FlutterWindowsView> view =
1449 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1450 false, BoxConstraints());
1453 view->OnUpdateSemanticsEnabled(
true);
1455 auto bridge = view->accessibility_bridge().lock();
1456 ASSERT_TRUE(bridge);
1458 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1460 root.label =
"root";
1463 root.increased_value =
"";
1464 root.decreased_value =
"";
1465 root.tooltip =
"tooltip";
1466 root.child_count = 0;
1467 root.custom_accessibility_actions_count = 0;
1468 auto flags = FlutterSemanticsFlags{
1469 .is_text_field =
true,
1471 root.flags2 = &flags;
1472 bridge->AddFlutterSemanticsNodeUpdate(root);
1474 bridge->CommitUpdates();
1475 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1476 std::string tooltip = root_node->GetData().GetStringAttribute(
1477 ax::mojom::StringAttribute::kTooltip);
1478 EXPECT_EQ(tooltip,
"tooltip");
1481 IAccessible* native_view = bridge->GetFlutterPlatformNodeDelegateFromID(0)
1483 ->GetNativeViewAccessible();
1484 VARIANT varchild = {.vt = VT_I4, .lVal = CHILDID_SELF};
1486 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
1487 EXPECT_NE(std::wcsstr(bname, L
"tooltip"),
nullptr);
1490 IRawElementProviderSimple* uia_node;
1491 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1493 ASSERT_EQ(uia_node->GetPropertyValue(UIA_HelpTextPropertyId, &varname), S_OK);
1494 std::string uia_tooltip = _com_util::ConvertBSTRToString(varname.bstrVal);
1495 EXPECT_EQ(uia_tooltip,
"tooltip");
1500 TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) {
1501 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1502 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1503 auto egl_manager = std::make_unique<egl::MockManager>();
1504 egl::MockContext render_context;
1505 auto surface = std::make_unique<egl::MockWindowSurface>();
1506 auto surface_ptr = surface.get();
1508 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1509 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1511 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1512 .WillOnce(Return(
true));
1514 EXPECT_CALL(*egl_manager.get(), render_context)
1515 .WillOnce(Return(&render_context));
1516 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1519 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1520 .WillOnce(Return(std::move(surface)));
1521 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1522 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1523 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1525 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1527 EngineModifier modifier{engine.get()};
1528 modifier.SetEGLManager(std::move(egl_manager));
1530 std::unique_ptr<FlutterWindowsView> view =
1531 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1532 false, BoxConstraints());
1537 TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) {
1538 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1539 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1540 auto egl_manager = std::make_unique<egl::MockManager>();
1541 egl::MockContext render_context;
1542 auto surface = std::make_unique<egl::MockWindowSurface>();
1543 auto surface_ptr = surface.get();
1545 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1546 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1547 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1548 .WillOnce(Return(
false));
1550 EXPECT_CALL(*egl_manager.get(), render_context)
1551 .WillOnce(Return(&render_context));
1552 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1555 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1556 .WillOnce(Return(std::move(surface)));
1557 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1558 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1559 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1561 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1563 EngineModifier modifier{engine.get()};
1564 modifier.SetEGLManager(std::move(egl_manager));
1566 std::unique_ptr<FlutterWindowsView> view =
1567 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1568 false, BoxConstraints());
1573 TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) {
1574 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1575 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1576 auto egl_manager = std::make_unique<egl::MockManager>();
1577 egl::MockContext render_context;
1578 auto surface = std::make_unique<egl::MockWindowSurface>();
1579 auto surface_ptr = surface.get();
1581 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1582 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1583 .WillOnce(Return(
true));
1585 EXPECT_CALL(*egl_manager.get(), render_context)
1586 .WillOnce(Return(&render_context));
1587 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1590 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1591 .WillOnce(Return(std::move(surface)));
1592 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1593 .WillOnce([](fml::closure
callback) {
1597 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1598 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1599 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1600 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1601 .WillOnce([](fml::closure
callback) {
1605 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1607 EngineModifier modifier{engine.get()};
1608 modifier.SetEGLManager(std::move(egl_manager));
1610 std::unique_ptr<FlutterWindowsView> view =
1611 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1612 false, BoxConstraints());
1617 TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) {
1618 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1619 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1620 auto egl_manager = std::make_unique<egl::MockManager>();
1621 egl::MockContext render_context;
1622 auto surface = std::make_unique<egl::MockWindowSurface>();
1623 auto surface_ptr = surface.get();
1625 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1627 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1628 .WillOnce(Return(
false));
1630 EXPECT_CALL(*egl_manager.get(), render_context)
1631 .WillOnce(Return(&render_context));
1632 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1635 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1636 .WillOnce(Return(std::move(surface)));
1637 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1638 .WillOnce([](fml::closure
callback) {
1643 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1644 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1645 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1647 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1648 .WillOnce([](fml::closure
callback) {
1652 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1654 EngineModifier modifier{engine.get()};
1655 modifier.SetEGLManager(std::move(egl_manager));
1657 std::unique_ptr<FlutterWindowsView> view =
1658 engine->CreateView(std::make_unique<NiceMock<MockWindowBindingHandler>>(),
1659 false, BoxConstraints());
1665 TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) {
1666 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1667 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1668 auto egl_manager = std::make_unique<egl::MockManager>();
1669 egl::MockContext render_context;
1670 auto surface = std::make_unique<egl::MockWindowSurface>();
1671 auto surface_ptr = surface.get();
1673 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1675 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1676 .WillRepeatedly([](fml::closure
callback) {
1681 EXPECT_CALL(*egl_manager.get(), render_context)
1682 .WillRepeatedly(Return(&render_context));
1684 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
1685 EXPECT_CALL(*surface_ptr, MakeCurrent).WillRepeatedly(Return(
true));
1686 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1687 EXPECT_CALL(render_context, ClearCurrent).WillRepeatedly(Return(
true));
1692 std::unique_ptr<FlutterWindowsView> view;
1694 EXPECT_CALL(*egl_manager, CreateWindowSurface)
1695 .WillOnce(Return(std::move(surface)));
1696 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1697 .WillOnce(Return(
true));
1698 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
1700 EngineModifier engine_modifier{engine.get()};
1701 engine_modifier.SetEGLManager(std::move(egl_manager));
1703 view = engine->CreateView(
1704 std::make_unique<NiceMock<MockWindowBindingHandler>>(),
false,
1710 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1711 .WillOnce(Return(
false));
1712 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1714 engine->OnDwmCompositionChanged();
1719 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1720 .WillOnce(Return(
true));
1721 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1723 engine->OnDwmCompositionChanged();
1727 TEST(FlutterWindowsViewTest, FocusTriggersWindowFocus) {
1728 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1729 auto window_binding_handler =
1730 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1731 EXPECT_CALL(*window_binding_handler, Focus()).WillOnce(Return(
true));
1732 std::unique_ptr<FlutterWindowsView> view =
1733 engine->CreateView(std::move(window_binding_handler),
1734 false, BoxConstraints());
1735 EXPECT_TRUE(view->Focus());
1738 TEST(FlutterWindowsViewTest, OnFocusTriggersSendFocusViewEvent) {
1739 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1740 auto window_binding_handler =
1741 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1742 std::unique_ptr<FlutterWindowsView> view =
1743 engine->CreateView(std::move(window_binding_handler),
1744 false, BoxConstraints());
1746 EngineModifier modifier(engine.get());
1747 bool received_focus_event =
false;
1748 modifier.embedder_api().SendViewFocusEvent = MOCK_ENGINE_PROC(
1749 SendViewFocusEvent, [&](FLUTTER_API_SYMBOL(
FlutterEngine) raw_engine,
1750 FlutterViewFocusEvent
const* event) {
1751 EXPECT_EQ(event->state, FlutterViewFocusState::kFocused);
1752 EXPECT_EQ(event->direction, FlutterViewFocusDirection::kUndefined);
1753 EXPECT_EQ(event->view_id, view->view_id());
1754 EXPECT_EQ(event->struct_size,
sizeof(FlutterViewFocusEvent));
1755 received_focus_event =
true;
1758 view->OnFocus(FlutterViewFocusState::kFocused,
1759 FlutterViewFocusDirection::kUndefined);
1760 EXPECT_TRUE(received_focus_event);
1763 TEST(FlutterWindowsViewTest, WindowMetricsEventContainsDisplayId) {
1764 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1765 EngineModifier modifier(engine.get());
1767 auto window_binding_handler =
1768 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1769 EXPECT_CALL(*window_binding_handler, GetDisplayId)
1770 .WillOnce(testing::Return(12));
1772 std::move(window_binding_handler),
false,
1775 FlutterWindowMetricsEvent
event = view.CreateWindowMetricsEvent();
1776 EXPECT_EQ(event.display_id, 12);
1779 TEST(FlutterWindowsViewTest, SizeChangeTriggersMetricsEventWhichHasDisplayId) {
1780 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1781 EngineModifier modifier(engine.get());
1783 auto window_binding_handler =
1784 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1785 EXPECT_CALL(*window_binding_handler, GetDisplayId)
1786 .WillOnce(testing::Return(12));
1788 std::move(window_binding_handler),
false,
1791 bool received_metrics =
false;
1792 modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1793 SendWindowMetricsEvent,
1794 ([&received_metrics](
auto engine,
1795 const FlutterWindowMetricsEvent* event) {
1796 received_metrics =
true;
1797 EXPECT_EQ(event->display_id, 12);
1800 view.OnWindowSizeChanged(100, 100);
1801 EXPECT_TRUE(received_metrics);
std::shared_ptr< FlutterPlatformNodeDelegateWindows > node_delegate
Controls a view that displays Flutter content.
static const JsonMessageCodec & GetInstance()
std::unique_ptr< std::vector< uint8_t > > EncodeMessage(const T &message) const
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
void(* VoidCallback)(void *)
FlutterDesktopBinaryReply callback
constexpr uint64_t kScanCodeKeyA
TEST(AccessibilityBridgeWindows, GetParent)
constexpr uint64_t kVirtualKeyA
constexpr FlutterViewId kImplicitViewId
const wchar_t * icu_data_path
const wchar_t * assets_path
const wchar_t * aot_library_path