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));
151 view->OnUpdateSemanticsEnabled(
true);
153 auto bridge = view->accessibility_bridge().lock();
156 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
161 root.increased_value =
"";
162 root.decreased_value =
"";
163 root.child_count = 0;
164 root.custom_accessibility_actions_count = 0;
165 auto flags = FlutterSemanticsFlags{
166 .is_expanded = FlutterTristate::kFlutterTristateTrue,
168 root.flags2 = &flags;
170 bridge->AddFlutterSemanticsNodeUpdate(root);
172 bridge->CommitUpdates();
175 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
176 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kExpanded));
179 IAccessible* native_view = root_node->GetNativeViewAccessible();
180 ASSERT_TRUE(native_view !=
nullptr);
183 VARIANT varchild = {};
187 varchild.lVal = CHILDID_SELF;
188 VARIANT native_state = {};
189 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
190 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_EXPANDED);
193 IRawElementProviderSimple* uia_node;
194 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
195 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
196 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
197 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Expanded);
199 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
200 UIA_AriaPropertiesPropertyId, &native_state)));
201 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=true"),
nullptr);
205 auto updated_flags = FlutterSemanticsFlags{
206 .is_expanded = FlutterTristate::kFlutterTristateFalse,
208 root.flags2 = &updated_flags;
210 bridge->AddFlutterSemanticsNodeUpdate(root);
211 bridge->CommitUpdates();
214 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
215 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kCollapsed));
218 IAccessible* native_view = root_node->GetNativeViewAccessible();
219 ASSERT_TRUE(native_view !=
nullptr);
222 VARIANT varchild = {};
226 varchild.lVal = CHILDID_SELF;
227 VARIANT native_state = {};
228 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
229 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_COLLAPSED);
232 IRawElementProviderSimple* uia_node;
233 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
234 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
235 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
236 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Collapsed);
238 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
239 UIA_AriaPropertiesPropertyId, &native_state)));
240 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=false"),
nullptr);
246 TEST(FlutterWindowsViewTest, Shutdown) {
247 auto engine = std::make_unique<MockFlutterWindowsEngine>();
248 auto window_binding_handler =
249 std::make_unique<NiceMock<MockWindowBindingHandler>>();
250 auto egl_manager = std::make_unique<egl::MockManager>();
251 auto surface = std::make_unique<egl::MockWindowSurface>();
252 egl::MockContext render_context;
254 auto engine_ptr = engine.get();
255 auto surface_ptr = surface.get();
256 auto egl_manager_ptr = egl_manager.get();
258 EngineModifier modifier{engine.get()};
259 modifier.SetEGLManager(std::move(egl_manager));
262 std::unique_ptr<FlutterWindowsView> view;
266 EXPECT_CALL(*egl_manager_ptr, CreateWindowSurface)
267 .WillOnce(Return(std::move(surface)));
268 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
false));
269 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
270 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
271 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
272 EXPECT_CALL(*egl_manager_ptr, render_context)
273 .WillOnce(Return(&render_context));
274 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
276 view = engine->CreateView(std::move(window_binding_handler));
281 auto view_id = view->view_id();
284 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
true));
285 EXPECT_CALL(*engine_ptr, RemoveView(view_id)).Times(1);
286 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
true));
287 EXPECT_CALL(*engine_ptr, PostRasterThreadTask)
288 .WillOnce([](fml::closure
callback) {
292 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
296 TEST(FlutterWindowsViewTest, KeySequence) {
297 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
299 test_response =
false;
301 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
302 std::make_unique<NiceMock<MockWindowBindingHandler>>());
305 [](
bool handled) {});
307 EXPECT_EQ(key_event_logs.size(), 2);
308 EXPECT_EQ(key_event_logs[0], kKeyEventFromEmbedder);
309 EXPECT_EQ(key_event_logs[1], kKeyEventFromChannel);
311 key_event_logs.clear();
314 TEST(FlutterWindowsViewTest, KeyEventCallback) {
315 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
317 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
318 std::make_unique<NiceMock<MockWindowBindingHandler>>());
322 MOCK_METHOD(
void, Call, ());
325 NiceMock<MockCallback> callback_with_valid_view;
326 NiceMock<MockCallback> callback_with_invalid_view;
328 auto trigger_key_event = [&](NiceMock<MockCallback>&
callback) {
333 EXPECT_CALL(callback_with_valid_view, Call()).Times(1);
334 EXPECT_CALL(callback_with_invalid_view, Call()).Times(0);
336 trigger_key_event(callback_with_valid_view);
337 engine->RemoveView(view->view_id());
338 trigger_key_event(callback_with_invalid_view);
340 key_event_logs.clear();
343 TEST(FlutterWindowsViewTest, EnableSemantics) {
344 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
345 EngineModifier modifier(engine.get());
347 bool semantics_enabled =
false;
348 modifier.embedder_api().UpdateSemanticsEnabled = MOCK_ENGINE_PROC(
349 UpdateSemanticsEnabled,
350 [&semantics_enabled](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
352 semantics_enabled = enabled;
356 auto window_binding_handler =
357 std::make_unique<NiceMock<MockWindowBindingHandler>>();
358 std::unique_ptr<FlutterWindowsView> view =
359 engine->CreateView(std::move(window_binding_handler));
361 view->OnUpdateSemanticsEnabled(
true);
362 EXPECT_TRUE(semantics_enabled);
365 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdate) {
366 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
367 EngineModifier modifier(engine.get());
368 modifier.embedder_api().UpdateSemanticsEnabled =
373 auto window_binding_handler =
374 std::make_unique<NiceMock<MockWindowBindingHandler>>();
375 std::unique_ptr<FlutterWindowsView> view =
376 engine->CreateView(std::move(window_binding_handler));
379 view->OnUpdateSemanticsEnabled(
true);
381 auto bridge = view->accessibility_bridge().lock();
385 FlutterSemanticsNode2 node{
sizeof(FlutterSemanticsNode2), 0};
387 node.value =
"value";
388 node.platform_view_id = -1;
389 auto flags = FlutterSemanticsFlags{};
390 node.flags2 = &flags;
391 bridge->AddFlutterSemanticsNodeUpdate(node);
392 bridge->CommitUpdates();
395 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
400 IAccessible* native_view =
node_delegate->GetNativeViewAccessible();
401 ASSERT_TRUE(native_view !=
nullptr);
406 varchild.lVal = CHILDID_SELF;
409 BSTR bname =
nullptr;
410 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
411 std::string name(_com_util::ConvertBSTRToString(bname));
412 EXPECT_EQ(name,
"name");
415 BSTR bvalue =
nullptr;
416 ASSERT_EQ(native_view->get_accValue(varchild, &bvalue), S_OK);
417 std::string value(_com_util::ConvertBSTRToString(bvalue));
418 EXPECT_EQ(value,
"value");
423 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
424 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
427 IRawElementProviderSimple* uia_view;
428 native_view->QueryInterface(IID_PPV_ARGS(&uia_view));
429 ASSERT_TRUE(uia_view !=
nullptr);
433 ASSERT_EQ(uia_view->GetPropertyValue(UIA_NamePropertyId, &varname), S_OK);
434 EXPECT_EQ(varname.vt, VT_BSTR);
435 name = _com_util::ConvertBSTRToString(varname.bstrVal);
436 EXPECT_EQ(name,
"name");
440 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue),
442 EXPECT_EQ(varvalue.vt, VT_BSTR);
443 value = _com_util::ConvertBSTRToString(varvalue.bstrVal);
444 EXPECT_EQ(value,
"value");
448 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
450 EXPECT_EQ(varrole.vt, VT_I4);
451 EXPECT_EQ(varrole.lVal, UIA_TextControlTypeId);
466 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdateWithChildren) {
467 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
468 EngineModifier modifier(engine.get());
469 modifier.embedder_api().UpdateSemanticsEnabled =
474 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
475 std::make_unique<NiceMock<MockWindowBindingHandler>>());
478 view->OnUpdateSemanticsEnabled(
true);
480 auto bridge = view->accessibility_bridge().lock();
484 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
485 std::vector<int32_t> node0_children{1, 2};
486 node0.child_count = node0_children.size();
487 node0.children_in_traversal_order = node0_children.data();
488 node0.children_in_hit_test_order = node0_children.data();
489 auto empty_flags = FlutterSemanticsFlags{};
490 node0.flags2 = &empty_flags;
492 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
493 node1.label =
"prefecture";
494 node1.value =
"Kyoto";
495 node1.flags2 = &empty_flags;
496 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
497 std::vector<int32_t> node2_children{3};
498 node2.child_count = node2_children.size();
499 node2.children_in_traversal_order = node2_children.data();
500 node2.children_in_hit_test_order = node2_children.data();
501 node2.flags2 = &empty_flags;
502 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
503 node3.label =
"city";
505 node3.flags2 = &empty_flags;
507 bridge->AddFlutterSemanticsNodeUpdate(node0);
508 bridge->AddFlutterSemanticsNodeUpdate(node1);
509 bridge->AddFlutterSemanticsNodeUpdate(node2);
510 bridge->AddFlutterSemanticsNodeUpdate(node3);
511 bridge->CommitUpdates();
514 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
519 IAccessible* node0_accessible =
node_delegate->GetNativeViewAccessible();
520 ASSERT_TRUE(node0_accessible !=
nullptr);
525 varchild.lVal = CHILDID_SELF;
530 ASSERT_EQ(node0_accessible->get_accRole(varchild, &varrole), S_OK);
531 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
534 long node0_child_count = 0;
535 ASSERT_EQ(node0_accessible->get_accChildCount(&node0_child_count), S_OK);
536 EXPECT_EQ(node0_child_count, 2);
541 IDispatch* node1_dispatch =
nullptr;
542 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node1_dispatch), S_OK);
543 ASSERT_TRUE(node1_dispatch !=
nullptr);
544 IAccessible* node1_accessible =
nullptr;
545 ASSERT_EQ(node1_dispatch->QueryInterface(
546 IID_IAccessible,
reinterpret_cast<void**
>(&node1_accessible)),
548 ASSERT_TRUE(node1_accessible !=
nullptr);
551 varchild.lVal = CHILDID_SELF;
552 BSTR bname =
nullptr;
553 ASSERT_EQ(node1_accessible->get_accName(varchild, &bname), S_OK);
554 std::string name(_com_util::ConvertBSTRToString(bname));
555 EXPECT_EQ(name,
"prefecture");
558 BSTR bvalue =
nullptr;
559 ASSERT_EQ(node1_accessible->get_accValue(varchild, &bvalue), S_OK);
560 std::string value(_com_util::ConvertBSTRToString(bvalue));
561 EXPECT_EQ(value,
"Kyoto");
566 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
567 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
570 IDispatch* parent_dispatch;
571 node1_accessible->get_accParent(&parent_dispatch);
572 IAccessible* parent_accessible;
574 parent_dispatch->QueryInterface(
575 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
577 EXPECT_EQ(parent_accessible, node0_accessible);
582 IDispatch* node2_dispatch =
nullptr;
583 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
584 ASSERT_TRUE(node2_dispatch !=
nullptr);
585 IAccessible* node2_accessible =
nullptr;
586 ASSERT_EQ(node2_dispatch->QueryInterface(
587 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
589 ASSERT_TRUE(node2_accessible !=
nullptr);
593 long node2_child_count = 0;
594 ASSERT_EQ(node2_accessible->get_accChildCount(&node2_child_count), S_OK);
595 EXPECT_EQ(node2_child_count, 1);
598 varchild.lVal = CHILDID_SELF;
601 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
602 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
605 IDispatch* parent_dispatch;
606 node2_accessible->get_accParent(&parent_dispatch);
607 IAccessible* parent_accessible;
609 parent_dispatch->QueryInterface(
610 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
612 EXPECT_EQ(parent_accessible, node0_accessible);
618 IDispatch* node3_dispatch =
nullptr;
619 ASSERT_EQ(node2_accessible->get_accChild(varchild, &node3_dispatch), S_OK);
620 ASSERT_TRUE(node3_dispatch !=
nullptr);
621 IAccessible* node3_accessible =
nullptr;
622 ASSERT_EQ(node3_dispatch->QueryInterface(
623 IID_IAccessible,
reinterpret_cast<void**
>(&node3_accessible)),
625 ASSERT_TRUE(node3_accessible !=
nullptr);
628 varchild.lVal = CHILDID_SELF;
629 BSTR bname =
nullptr;
630 ASSERT_EQ(node3_accessible->get_accName(varchild, &bname), S_OK);
631 std::string name(_com_util::ConvertBSTRToString(bname));
632 EXPECT_EQ(name,
"city");
635 BSTR bvalue =
nullptr;
636 ASSERT_EQ(node3_accessible->get_accValue(varchild, &bvalue), S_OK);
637 std::string value(_com_util::ConvertBSTRToString(bvalue));
638 EXPECT_EQ(value,
"Uji");
643 ASSERT_EQ(node3_accessible->get_accRole(varchild, &varrole), S_OK);
644 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
647 IDispatch* parent_dispatch;
648 node3_accessible->get_accParent(&parent_dispatch);
649 IAccessible* parent_accessible;
651 parent_dispatch->QueryInterface(
652 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
654 EXPECT_EQ(parent_accessible, node2_accessible);
667 TEST(FlutterWindowsViewTest, NonZeroSemanticsRoot) {
668 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
669 EngineModifier modifier(engine.get());
670 modifier.embedder_api().UpdateSemanticsEnabled =
675 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
676 std::make_unique<NiceMock<MockWindowBindingHandler>>());
679 view->OnUpdateSemanticsEnabled(
true);
681 auto bridge = view->accessibility_bridge().lock();
685 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
686 std::vector<int32_t> node1_children{2};
687 node1.child_count = node1_children.size();
688 node1.children_in_traversal_order = node1_children.data();
689 node1.children_in_hit_test_order = node1_children.data();
690 auto empty_flags = FlutterSemanticsFlags{};
691 node1.flags2 = &empty_flags;
693 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
694 node2.label =
"prefecture";
695 node2.value =
"Kyoto";
696 node2.flags2 = &empty_flags;
697 bridge->AddFlutterSemanticsNodeUpdate(node1);
698 bridge->AddFlutterSemanticsNodeUpdate(node2);
699 bridge->CommitUpdates();
702 auto root_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
703 ASSERT_TRUE(root_delegate);
704 EXPECT_EQ(root_delegate->GetChildCount(), 1);
707 auto child_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
708 ASSERT_TRUE(child_delegate);
709 EXPECT_EQ(child_delegate->GetChildCount(), 0);
712 auto fake_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
713 ASSERT_FALSE(fake_delegate);
716 IAccessible* node1_accessible = root_delegate->GetNativeViewAccessible();
717 ASSERT_TRUE(node1_accessible !=
nullptr);
722 varchild.lVal = CHILDID_SELF;
727 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
728 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
731 long node1_child_count = 0;
732 ASSERT_EQ(node1_accessible->get_accChildCount(&node1_child_count), S_OK);
733 EXPECT_EQ(node1_child_count, 1);
738 IDispatch* node2_dispatch =
nullptr;
739 ASSERT_EQ(node1_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
740 ASSERT_TRUE(node2_dispatch !=
nullptr);
741 IAccessible* node2_accessible =
nullptr;
742 ASSERT_EQ(node2_dispatch->QueryInterface(
743 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
745 ASSERT_TRUE(node2_accessible !=
nullptr);
748 varchild.lVal = CHILDID_SELF;
749 BSTR bname =
nullptr;
750 ASSERT_EQ(node2_accessible->get_accName(varchild, &bname), S_OK);
751 std::string name(_com_util::ConvertBSTRToString(bname));
752 EXPECT_EQ(name,
"prefecture");
755 BSTR bvalue =
nullptr;
756 ASSERT_EQ(node2_accessible->get_accValue(varchild, &bvalue), S_OK);
757 std::string value(_com_util::ConvertBSTRToString(bvalue));
758 EXPECT_EQ(value,
"Kyoto");
763 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
764 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
767 IDispatch* parent_dispatch;
768 node2_accessible->get_accParent(&parent_dispatch);
769 IAccessible* parent_accessible;
771 parent_dispatch->QueryInterface(
772 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
774 EXPECT_EQ(parent_accessible, node1_accessible);
795 TEST(FlutterWindowsViewTest, AccessibilityHitTesting) {
796 constexpr FlutterTransformation kIdentityTransform = {1, 0, 0,
800 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
801 EngineModifier modifier(engine.get());
802 modifier.embedder_api().UpdateSemanticsEnabled =
807 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
808 std::make_unique<NiceMock<MockWindowBindingHandler>>());
811 view->OnUpdateSemanticsEnabled(
true);
813 auto bridge = view->accessibility_bridge().lock();
817 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
818 auto empty_flags = FlutterSemanticsFlags{};
819 std::vector<int32_t> node0_children{1, 2};
820 node0.rect = {0, 0, 500, 500};
821 node0.transform = kIdentityTransform;
822 node0.child_count = node0_children.size();
823 node0.children_in_traversal_order = node0_children.data();
824 node0.children_in_hit_test_order = node0_children.data();
825 node0.flags2 = &empty_flags;
828 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
829 node1.rect = {0, 0, 250, 500};
830 node1.transform = kIdentityTransform;
831 node1.label =
"prefecture";
832 node1.value =
"Kyoto";
833 node1.flags2 = &empty_flags;
836 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
837 std::vector<int32_t> node2_children{3};
838 node2.rect = {0, 0, 250, 500};
839 node2.transform = {1, 0, 250, 0, 1, 0, 0, 0, 1};
840 node2.child_count = node2_children.size();
841 node2.children_in_traversal_order = node2_children.data();
842 node2.children_in_hit_test_order = node2_children.data();
843 node2.flags2 = &empty_flags;
846 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
847 node3.rect = {0, 0, 250, 250};
848 node3.transform = {1, 0, 0, 0, 1, 250, 0, 0, 1};
849 node3.label =
"city";
851 node3.flags2 = &empty_flags;
853 bridge->AddFlutterSemanticsNodeUpdate(node0);
854 bridge->AddFlutterSemanticsNodeUpdate(node1);
855 bridge->AddFlutterSemanticsNodeUpdate(node2);
856 bridge->AddFlutterSemanticsNodeUpdate(node3);
857 bridge->CommitUpdates();
860 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
861 ASSERT_TRUE(node0_delegate);
862 auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
863 ASSERT_TRUE(node1_delegate);
864 auto node2_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
865 ASSERT_TRUE(node2_delegate);
866 auto node3_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(3).lock();
867 ASSERT_TRUE(node3_delegate);
870 IAccessible* node0_accessible = node0_delegate->GetNativeViewAccessible();
871 ASSERT_TRUE(node0_accessible !=
nullptr);
875 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(150, 150, &varchild)));
876 EXPECT_EQ(varchild.vt, VT_DISPATCH);
877 EXPECT_EQ(varchild.pdispVal, node1_delegate->GetNativeViewAccessible());
881 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 150, &varchild)));
882 EXPECT_EQ(varchild.vt, VT_DISPATCH);
883 EXPECT_EQ(varchild.pdispVal, node2_delegate->GetNativeViewAccessible());
887 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 450, &varchild)));
888 EXPECT_EQ(varchild.vt, VT_DISPATCH);
889 EXPECT_EQ(varchild.pdispVal, node3_delegate->GetNativeViewAccessible());
892 TEST(FlutterWindowsViewTest, WindowResizeTests) {
893 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
894 std::unique_ptr<FlutterWindowsEngine> engine =
895 GetTestEngine(windows_proc_table);
897 EngineModifier engine_modifier{engine.get()};
898 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
899 PostRenderThreadTask,
905 auto egl_manager = std::make_unique<egl::MockManager>();
906 auto surface = std::make_unique<egl::MockWindowSurface>();
907 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
908 egl::MockContext render_context;
910 auto surface_ptr = surface.get();
911 auto resized_surface_ptr = resized_surface.get();
914 EXPECT_CALL(*egl_manager, CreateWindowSurface)
915 .WillOnce(Return(std::move(surface)));
916 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
917 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
918 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
919 EXPECT_CALL(*egl_manager, render_context).WillOnce(Return(&render_context));
920 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
923 EXPECT_CALL(*surface_ptr, Destroy).WillOnce(Return(
true));
924 EXPECT_CALL(*egl_manager.get(),
925 CreateWindowSurface(_, 500, 500))
926 .WillOnce(Return(std::move((resized_surface))));
927 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
928 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
929 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
931 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
933 engine_modifier.SetEGLManager(std::move(egl_manager));
935 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
936 std::make_unique<NiceMock<MockWindowBindingHandler>>());
938 fml::AutoResetWaitableEvent metrics_sent_latch;
939 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
940 SendWindowMetricsEvent,
941 ([&metrics_sent_latch](
auto engine,
942 const FlutterWindowMetricsEvent* event) {
943 metrics_sent_latch.Signal();
948 std::thread frame_thread([&metrics_sent_latch, &view]() {
949 metrics_sent_latch.Wait();
951 EXPECT_TRUE(view->OnFrameGenerated(500, 500));
952 view->OnFramePresented();
958 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
963 TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) {
964 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
965 std::unique_ptr<FlutterWindowsEngine> engine =
966 GetTestEngine(windows_proc_table);
968 EngineModifier engine_modifier{engine.get()};
969 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
970 PostRenderThreadTask,
976 auto egl_manager = std::make_unique<egl::MockManager>();
977 auto surface = std::make_unique<egl::MockWindowSurface>();
978 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
979 auto resized_surface_ptr = resized_surface.get();
981 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
982 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
984 EXPECT_CALL(*egl_manager.get(),
985 CreateWindowSurface(_, 500, 500))
986 .WillOnce(Return(std::move((resized_surface))));
987 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
988 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
989 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
991 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
993 fml::AutoResetWaitableEvent metrics_sent_latch;
994 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
995 SendWindowMetricsEvent,
996 ([&metrics_sent_latch](
auto engine,
997 const FlutterWindowMetricsEvent* event) {
998 metrics_sent_latch.Signal();
1002 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1003 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1005 ViewModifier view_modifier{view.get()};
1006 engine_modifier.SetEGLManager(std::move(egl_manager));
1007 view_modifier.SetSurface(std::move(surface));
1010 std::thread frame_thread([&metrics_sent_latch, &view]() {
1011 metrics_sent_latch.Wait();
1014 EXPECT_TRUE(view->OnEmptyFrameGenerated());
1015 view->OnFramePresented();
1020 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
1021 frame_thread.join();
1027 TEST(FlutterWindowsViewTest, WindowResizeRace) {
1028 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1030 EngineModifier engine_modifier(engine.get());
1031 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
1032 PostRenderThreadTask,
1038 auto egl_manager = std::make_unique<egl::MockManager>();
1039 auto surface = std::make_unique<egl::MockWindowSurface>();
1041 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
1042 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
1044 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1045 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1047 ViewModifier view_modifier{view.get()};
1048 engine_modifier.SetEGLManager(std::move(egl_manager));
1049 view_modifier.SetSurface(std::move(surface));
1052 ASSERT_TRUE(view->OnFrameGenerated(100, 100));
1056 EXPECT_FALSE(view->OnWindowSizeChanged(500, 500));
1061 view->OnFramePresented();
1066 TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) {
1067 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1069 EngineModifier engine_modifier(engine.get());
1070 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
1071 PostRenderThreadTask,
1077 auto egl_manager = std::make_unique<egl::MockManager>();
1078 auto surface = std::make_unique<egl::MockWindowSurface>();
1080 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1081 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
false));
1082 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
false));
1084 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1085 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1087 ViewModifier view_modifier{view.get()};
1088 engine_modifier.SetEGLManager(std::move(egl_manager));
1089 view_modifier.SetSurface(std::move(surface));
1091 auto metrics_sent =
false;
1092 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1093 SendWindowMetricsEvent,
1094 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1095 metrics_sent =
true;
1099 view->OnWindowSizeChanged(500, 500);
1104 TEST(FlutterWindowsViewTest, WindowResizeWithoutSurface) {
1105 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1106 EngineModifier modifier(engine.get());
1108 auto egl_manager = std::make_unique<egl::MockManager>();
1110 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1112 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1113 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1115 modifier.SetEGLManager(std::move(egl_manager));
1117 auto metrics_sent =
false;
1118 modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1119 SendWindowMetricsEvent,
1120 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1121 metrics_sent =
true;
1125 view->OnWindowSizeChanged(500, 500);
1128 TEST(FlutterWindowsViewTest, WindowRepaintTests) {
1129 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1130 EngineModifier modifier(engine.get());
1133 std::make_unique<flutter::FlutterWindow>(100, 100)};
1135 bool schedule_frame_called =
false;
1136 modifier.embedder_api().ScheduleFrame =
1137 MOCK_ENGINE_PROC(ScheduleFrame, ([&schedule_frame_called](
auto engine) {
1138 schedule_frame_called =
true;
1142 view.OnWindowRepaint();
1143 EXPECT_TRUE(schedule_frame_called);
1152 TEST(FlutterWindowsViewTest, CheckboxNativeState) {
1153 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1154 EngineModifier modifier(engine.get());
1155 modifier.embedder_api().UpdateSemanticsEnabled =
1156 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1160 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1161 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1164 view->OnUpdateSemanticsEnabled(
true);
1166 auto bridge = view->accessibility_bridge().lock();
1167 ASSERT_TRUE(bridge);
1169 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1171 root.label =
"root";
1174 root.increased_value =
"";
1175 root.decreased_value =
"";
1176 root.child_count = 0;
1177 root.custom_accessibility_actions_count = 0;
1178 auto flags = FlutterSemanticsFlags{
1179 .is_checked = FlutterCheckState::kFlutterCheckStateTrue,
1181 root.flags2 = &flags;
1182 bridge->AddFlutterSemanticsNodeUpdate(root);
1184 bridge->CommitUpdates();
1187 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1188 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1189 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1190 ax::mojom::CheckedState::kTrue);
1193 IAccessible* native_view = root_node->GetNativeViewAccessible();
1194 ASSERT_TRUE(native_view !=
nullptr);
1197 VARIANT varchild = {};
1198 varchild.vt = VT_I4;
1201 varchild.lVal = CHILDID_SELF;
1202 VARIANT native_state = {};
1203 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1204 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1207 IRawElementProviderSimple* uia_node;
1208 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1209 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1210 UIA_ToggleToggleStatePropertyId, &native_state)));
1211 EXPECT_EQ(native_state.lVal, ToggleState_On);
1213 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1214 UIA_AriaPropertiesPropertyId, &native_state)));
1215 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=true"),
nullptr);
1219 auto updated_flags = FlutterSemanticsFlags{
1220 .is_checked = FlutterCheckState::kFlutterCheckStateFalse,
1222 root.flags2 = &updated_flags;
1223 bridge->AddFlutterSemanticsNodeUpdate(root);
1224 bridge->CommitUpdates();
1227 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1228 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1229 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1230 ax::mojom::CheckedState::kFalse);
1233 IAccessible* native_view = root_node->GetNativeViewAccessible();
1234 ASSERT_TRUE(native_view !=
nullptr);
1237 VARIANT varchild = {};
1238 varchild.vt = VT_I4;
1241 varchild.lVal = CHILDID_SELF;
1242 VARIANT native_state = {};
1243 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1244 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1247 IRawElementProviderSimple* uia_node;
1248 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1249 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1250 UIA_ToggleToggleStatePropertyId, &native_state)));
1251 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1253 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1254 UIA_AriaPropertiesPropertyId, &native_state)));
1255 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=false"),
nullptr);
1259 auto updated_mixe_flags = FlutterSemanticsFlags{
1260 .is_checked = FlutterCheckState::kFlutterCheckStateMixed,
1262 root.flags2 = &updated_mixe_flags;
1263 bridge->AddFlutterSemanticsNodeUpdate(root);
1264 bridge->CommitUpdates();
1267 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1268 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1269 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1270 ax::mojom::CheckedState::kMixed);
1273 IAccessible* native_view = root_node->GetNativeViewAccessible();
1274 ASSERT_TRUE(native_view !=
nullptr);
1277 VARIANT varchild = {};
1278 varchild.vt = VT_I4;
1281 varchild.lVal = CHILDID_SELF;
1282 VARIANT native_state = {};
1283 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1284 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_MIXED);
1287 IRawElementProviderSimple* uia_node;
1288 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1289 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1290 UIA_ToggleToggleStatePropertyId, &native_state)));
1291 EXPECT_EQ(native_state.lVal, ToggleState_Indeterminate);
1293 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1294 UIA_AriaPropertiesPropertyId, &native_state)));
1295 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=mixed"),
nullptr);
1300 TEST(FlutterWindowsViewTest, SwitchNativeState) {
1301 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1302 EngineModifier modifier(engine.get());
1303 modifier.embedder_api().UpdateSemanticsEnabled =
1304 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1308 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1309 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1312 view->OnUpdateSemanticsEnabled(
true);
1314 auto bridge = view->accessibility_bridge().lock();
1315 ASSERT_TRUE(bridge);
1317 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1319 root.label =
"root";
1322 root.increased_value =
"";
1323 root.decreased_value =
"";
1324 root.child_count = 0;
1325 root.custom_accessibility_actions_count = 0;
1327 auto flags = FlutterSemanticsFlags{
1328 .is_toggled = FlutterTristate::kFlutterTristateTrue,
1330 root.flags2 = &flags;
1331 bridge->AddFlutterSemanticsNodeUpdate(root);
1333 bridge->CommitUpdates();
1336 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1337 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1338 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1339 ax::mojom::CheckedState::kTrue);
1342 IAccessible* native_view = root_node->GetNativeViewAccessible();
1343 ASSERT_TRUE(native_view !=
nullptr);
1346 VARIANT varchild = {};
1347 varchild.vt = VT_I4;
1349 varchild.lVal = CHILDID_SELF;
1350 VARIANT varrole = {};
1353 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
1354 ASSERT_EQ(varrole.lVal, ROLE_SYSTEM_CHECKBUTTON);
1357 VARIANT native_state = {};
1358 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1359 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_PRESSED);
1360 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1363 IRawElementProviderSimple* uia_node;
1364 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1365 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
1367 EXPECT_EQ(varrole.lVal, UIA_ButtonControlTypeId);
1368 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1371 EXPECT_EQ(native_state.lVal, ToggleState_On);
1373 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1375 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=true"),
nullptr);
1379 auto updated_flags = FlutterSemanticsFlags{
1380 .is_toggled = FlutterTristate::kFlutterTristateFalse,
1382 root.flags2 = &updated_flags;
1384 bridge->AddFlutterSemanticsNodeUpdate(root);
1385 bridge->CommitUpdates();
1388 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1389 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1390 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1391 ax::mojom::CheckedState::kFalse);
1394 IAccessible* native_view = root_node->GetNativeViewAccessible();
1395 ASSERT_TRUE(native_view !=
nullptr);
1398 VARIANT varchild = {};
1399 varchild.vt = VT_I4;
1402 varchild.lVal = CHILDID_SELF;
1403 VARIANT native_state = {};
1404 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1405 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_PRESSED);
1406 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1409 IRawElementProviderSimple* uia_node;
1410 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1411 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1414 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1416 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1418 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=false"),
nullptr);
1422 TEST(FlutterWindowsViewTest, TooltipNodeData) {
1423 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1424 EngineModifier modifier(engine.get());
1425 modifier.embedder_api().UpdateSemanticsEnabled =
1426 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1430 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1431 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1434 view->OnUpdateSemanticsEnabled(
true);
1436 auto bridge = view->accessibility_bridge().lock();
1437 ASSERT_TRUE(bridge);
1439 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1441 root.label =
"root";
1444 root.increased_value =
"";
1445 root.decreased_value =
"";
1446 root.tooltip =
"tooltip";
1447 root.child_count = 0;
1448 root.custom_accessibility_actions_count = 0;
1449 auto flags = FlutterSemanticsFlags{
1450 .is_text_field =
true,
1452 root.flags2 = &flags;
1453 bridge->AddFlutterSemanticsNodeUpdate(root);
1455 bridge->CommitUpdates();
1456 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1457 std::string tooltip = root_node->GetData().GetStringAttribute(
1458 ax::mojom::StringAttribute::kTooltip);
1459 EXPECT_EQ(tooltip,
"tooltip");
1462 IAccessible* native_view = bridge->GetFlutterPlatformNodeDelegateFromID(0)
1464 ->GetNativeViewAccessible();
1465 VARIANT varchild = {.vt = VT_I4, .lVal = CHILDID_SELF};
1467 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
1468 EXPECT_NE(std::wcsstr(bname, L
"tooltip"),
nullptr);
1471 IRawElementProviderSimple* uia_node;
1472 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1474 ASSERT_EQ(uia_node->GetPropertyValue(UIA_HelpTextPropertyId, &varname), S_OK);
1475 std::string uia_tooltip = _com_util::ConvertBSTRToString(varname.bstrVal);
1476 EXPECT_EQ(uia_tooltip,
"tooltip");
1481 TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) {
1482 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1483 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1484 auto egl_manager = std::make_unique<egl::MockManager>();
1485 egl::MockContext render_context;
1486 auto surface = std::make_unique<egl::MockWindowSurface>();
1487 auto surface_ptr = surface.get();
1489 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1490 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1492 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1493 .WillOnce(Return(
true));
1495 EXPECT_CALL(*egl_manager.get(), render_context)
1496 .WillOnce(Return(&render_context));
1497 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1500 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1501 .WillOnce(Return(std::move(surface)));
1502 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1503 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1504 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1506 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1508 EngineModifier modifier{engine.get()};
1509 modifier.SetEGLManager(std::move(egl_manager));
1511 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1512 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1517 TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) {
1518 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1519 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1520 auto egl_manager = std::make_unique<egl::MockManager>();
1521 egl::MockContext render_context;
1522 auto surface = std::make_unique<egl::MockWindowSurface>();
1523 auto surface_ptr = surface.get();
1525 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1526 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1527 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1528 .WillOnce(Return(
false));
1530 EXPECT_CALL(*egl_manager.get(), render_context)
1531 .WillOnce(Return(&render_context));
1532 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1535 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1536 .WillOnce(Return(std::move(surface)));
1537 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1538 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1539 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1541 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1543 EngineModifier modifier{engine.get()};
1544 modifier.SetEGLManager(std::move(egl_manager));
1546 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1547 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1552 TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) {
1553 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1554 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1555 auto egl_manager = std::make_unique<egl::MockManager>();
1556 egl::MockContext render_context;
1557 auto surface = std::make_unique<egl::MockWindowSurface>();
1558 auto surface_ptr = surface.get();
1560 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1561 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1562 .WillOnce(Return(
true));
1564 EXPECT_CALL(*egl_manager.get(), render_context)
1565 .WillOnce(Return(&render_context));
1566 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1569 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1570 .WillOnce(Return(std::move(surface)));
1571 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1572 .WillOnce([](fml::closure
callback) {
1576 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1577 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1578 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1579 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1580 .WillOnce([](fml::closure
callback) {
1584 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1586 EngineModifier modifier{engine.get()};
1587 modifier.SetEGLManager(std::move(egl_manager));
1589 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1590 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1595 TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) {
1596 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1597 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1598 auto egl_manager = std::make_unique<egl::MockManager>();
1599 egl::MockContext render_context;
1600 auto surface = std::make_unique<egl::MockWindowSurface>();
1601 auto surface_ptr = surface.get();
1603 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1605 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1606 .WillOnce(Return(
false));
1608 EXPECT_CALL(*egl_manager.get(), render_context)
1609 .WillOnce(Return(&render_context));
1610 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1613 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1614 .WillOnce(Return(std::move(surface)));
1615 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1616 .WillOnce([](fml::closure
callback) {
1621 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1622 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1623 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1625 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1626 .WillOnce([](fml::closure
callback) {
1630 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1632 EngineModifier modifier{engine.get()};
1633 modifier.SetEGLManager(std::move(egl_manager));
1635 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1636 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1642 TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) {
1643 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1644 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1645 auto egl_manager = std::make_unique<egl::MockManager>();
1646 egl::MockContext render_context;
1647 auto surface = std::make_unique<egl::MockWindowSurface>();
1648 auto surface_ptr = surface.get();
1650 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1652 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1653 .WillRepeatedly([](fml::closure
callback) {
1658 EXPECT_CALL(*egl_manager.get(), render_context)
1659 .WillRepeatedly(Return(&render_context));
1661 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
1662 EXPECT_CALL(*surface_ptr, MakeCurrent).WillRepeatedly(Return(
true));
1663 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1664 EXPECT_CALL(render_context, ClearCurrent).WillRepeatedly(Return(
true));
1669 std::unique_ptr<FlutterWindowsView> view;
1671 EXPECT_CALL(*egl_manager, CreateWindowSurface)
1672 .WillOnce(Return(std::move(surface)));
1673 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1674 .WillOnce(Return(
true));
1675 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
1677 EngineModifier engine_modifier{engine.get()};
1678 engine_modifier.SetEGLManager(std::move(egl_manager));
1680 view = engine->CreateView(
1681 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1686 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1687 .WillOnce(Return(
false));
1688 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1690 engine->OnDwmCompositionChanged();
1695 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1696 .WillOnce(Return(
true));
1697 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1699 engine->OnDwmCompositionChanged();
1703 TEST(FlutterWindowsViewTest, FocusTriggersWindowFocus) {
1704 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1705 auto window_binding_handler =
1706 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1707 EXPECT_CALL(*window_binding_handler, Focus()).WillOnce(Return(
true));
1708 std::unique_ptr<FlutterWindowsView> view =
1709 engine->CreateView(std::move(window_binding_handler));
1710 EXPECT_TRUE(view->Focus());
1713 TEST(FlutterWindowsViewTest, OnFocusTriggersSendFocusViewEvent) {
1714 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1715 auto window_binding_handler =
1716 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1717 std::unique_ptr<FlutterWindowsView> view =
1718 engine->CreateView(std::move(window_binding_handler));
1720 EngineModifier modifier(engine.get());
1721 bool received_focus_event =
false;
1722 modifier.embedder_api().SendViewFocusEvent = MOCK_ENGINE_PROC(
1723 SendViewFocusEvent, [&](FLUTTER_API_SYMBOL(
FlutterEngine) raw_engine,
1724 FlutterViewFocusEvent
const* event) {
1725 EXPECT_EQ(event->state, FlutterViewFocusState::kFocused);
1726 EXPECT_EQ(event->direction, FlutterViewFocusDirection::kUndefined);
1727 EXPECT_EQ(event->view_id, view->view_id());
1728 EXPECT_EQ(event->struct_size,
sizeof(FlutterViewFocusEvent));
1729 received_focus_event =
true;
1732 view->OnFocus(FlutterViewFocusState::kFocused,
1733 FlutterViewFocusDirection::kUndefined);
1734 EXPECT_TRUE(received_focus_event);
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