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 root.flags =
static_cast<FlutterSemanticsFlag
>(
166 FlutterSemanticsFlag::kFlutterSemanticsFlagHasExpandedState |
167 FlutterSemanticsFlag::kFlutterSemanticsFlagIsExpanded);
168 bridge->AddFlutterSemanticsNodeUpdate(root);
170 bridge->CommitUpdates();
173 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
174 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kExpanded));
177 IAccessible* native_view = root_node->GetNativeViewAccessible();
178 ASSERT_TRUE(native_view !=
nullptr);
181 VARIANT varchild = {};
185 varchild.lVal = CHILDID_SELF;
186 VARIANT native_state = {};
187 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
188 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_EXPANDED);
191 IRawElementProviderSimple* uia_node;
192 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
193 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
194 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
195 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Expanded);
197 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
198 UIA_AriaPropertiesPropertyId, &native_state)));
199 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=true"),
nullptr);
203 root.flags =
static_cast<FlutterSemanticsFlag
>(
204 FlutterSemanticsFlag::kFlutterSemanticsFlagHasExpandedState);
205 bridge->AddFlutterSemanticsNodeUpdate(root);
206 bridge->CommitUpdates();
209 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
210 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kCollapsed));
213 IAccessible* native_view = root_node->GetNativeViewAccessible();
214 ASSERT_TRUE(native_view !=
nullptr);
217 VARIANT varchild = {};
221 varchild.lVal = CHILDID_SELF;
222 VARIANT native_state = {};
223 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
224 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_COLLAPSED);
227 IRawElementProviderSimple* uia_node;
228 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
229 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
230 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
231 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Collapsed);
233 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
234 UIA_AriaPropertiesPropertyId, &native_state)));
235 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=false"),
nullptr);
241 TEST(FlutterWindowsViewTest, Shutdown) {
242 auto engine = std::make_unique<MockFlutterWindowsEngine>();
243 auto window_binding_handler =
244 std::make_unique<NiceMock<MockWindowBindingHandler>>();
245 auto egl_manager = std::make_unique<egl::MockManager>();
246 auto surface = std::make_unique<egl::MockWindowSurface>();
247 egl::MockContext render_context;
249 auto engine_ptr = engine.get();
250 auto surface_ptr = surface.get();
251 auto egl_manager_ptr = egl_manager.get();
253 EngineModifier modifier{engine.get()};
254 modifier.SetEGLManager(std::move(egl_manager));
257 std::unique_ptr<FlutterWindowsView> view;
261 EXPECT_CALL(*egl_manager_ptr, CreateWindowSurface)
262 .WillOnce(Return(std::move(surface)));
263 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
false));
264 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
265 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
266 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
267 EXPECT_CALL(*egl_manager_ptr, render_context)
268 .WillOnce(Return(&render_context));
269 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
271 view = engine->CreateView(std::move(window_binding_handler));
276 auto view_id = view->view_id();
279 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
true));
280 EXPECT_CALL(*engine_ptr, RemoveView(view_id)).Times(1);
281 EXPECT_CALL(*engine_ptr, running).WillOnce(Return(
true));
282 EXPECT_CALL(*engine_ptr, PostRasterThreadTask)
283 .WillOnce([](fml::closure
callback) {
287 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
291 TEST(FlutterWindowsViewTest, KeySequence) {
292 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
294 test_response =
false;
296 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
297 std::make_unique<NiceMock<MockWindowBindingHandler>>());
300 [](
bool handled) {});
302 EXPECT_EQ(key_event_logs.size(), 2);
303 EXPECT_EQ(key_event_logs[0], kKeyEventFromEmbedder);
304 EXPECT_EQ(key_event_logs[1], kKeyEventFromChannel);
306 key_event_logs.clear();
309 TEST(FlutterWindowsViewTest, EnableSemantics) {
310 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
311 EngineModifier modifier(engine.get());
313 bool semantics_enabled =
false;
314 modifier.embedder_api().UpdateSemanticsEnabled = MOCK_ENGINE_PROC(
315 UpdateSemanticsEnabled,
316 [&semantics_enabled](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
318 semantics_enabled = enabled;
322 auto window_binding_handler =
323 std::make_unique<NiceMock<MockWindowBindingHandler>>();
324 std::unique_ptr<FlutterWindowsView> view =
325 engine->CreateView(std::move(window_binding_handler));
327 view->OnUpdateSemanticsEnabled(
true);
328 EXPECT_TRUE(semantics_enabled);
331 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdate) {
332 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
333 EngineModifier modifier(engine.get());
334 modifier.embedder_api().UpdateSemanticsEnabled =
339 auto window_binding_handler =
340 std::make_unique<NiceMock<MockWindowBindingHandler>>();
341 std::unique_ptr<FlutterWindowsView> view =
342 engine->CreateView(std::move(window_binding_handler));
345 view->OnUpdateSemanticsEnabled(
true);
347 auto bridge = view->accessibility_bridge().lock();
351 FlutterSemanticsNode2 node{
sizeof(FlutterSemanticsNode2), 0};
353 node.value =
"value";
354 node.platform_view_id = -1;
355 bridge->AddFlutterSemanticsNodeUpdate(node);
356 bridge->CommitUpdates();
359 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
364 IAccessible* native_view =
node_delegate->GetNativeViewAccessible();
365 ASSERT_TRUE(native_view !=
nullptr);
370 varchild.lVal = CHILDID_SELF;
373 BSTR bname =
nullptr;
374 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
375 std::string name(_com_util::ConvertBSTRToString(bname));
376 EXPECT_EQ(name,
"name");
379 BSTR bvalue =
nullptr;
380 ASSERT_EQ(native_view->get_accValue(varchild, &bvalue), S_OK);
381 std::string value(_com_util::ConvertBSTRToString(bvalue));
382 EXPECT_EQ(value,
"value");
387 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
388 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
391 IRawElementProviderSimple* uia_view;
392 native_view->QueryInterface(IID_PPV_ARGS(&uia_view));
393 ASSERT_TRUE(uia_view !=
nullptr);
397 ASSERT_EQ(uia_view->GetPropertyValue(UIA_NamePropertyId, &varname), S_OK);
398 EXPECT_EQ(varname.vt, VT_BSTR);
399 name = _com_util::ConvertBSTRToString(varname.bstrVal);
400 EXPECT_EQ(name,
"name");
404 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue),
406 EXPECT_EQ(varvalue.vt, VT_BSTR);
407 value = _com_util::ConvertBSTRToString(varvalue.bstrVal);
408 EXPECT_EQ(value,
"value");
412 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
414 EXPECT_EQ(varrole.vt, VT_I4);
415 EXPECT_EQ(varrole.lVal, UIA_TextControlTypeId);
430 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdateWithChildren) {
431 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
432 EngineModifier modifier(engine.get());
433 modifier.embedder_api().UpdateSemanticsEnabled =
438 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
439 std::make_unique<NiceMock<MockWindowBindingHandler>>());
442 view->OnUpdateSemanticsEnabled(
true);
444 auto bridge = view->accessibility_bridge().lock();
448 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
449 std::vector<int32_t> node0_children{1, 2};
450 node0.child_count = node0_children.size();
451 node0.children_in_traversal_order = node0_children.data();
452 node0.children_in_hit_test_order = node0_children.data();
454 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
455 node1.label =
"prefecture";
456 node1.value =
"Kyoto";
457 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
458 std::vector<int32_t> node2_children{3};
459 node2.child_count = node2_children.size();
460 node2.children_in_traversal_order = node2_children.data();
461 node2.children_in_hit_test_order = node2_children.data();
462 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
463 node3.label =
"city";
466 bridge->AddFlutterSemanticsNodeUpdate(node0);
467 bridge->AddFlutterSemanticsNodeUpdate(node1);
468 bridge->AddFlutterSemanticsNodeUpdate(node2);
469 bridge->AddFlutterSemanticsNodeUpdate(node3);
470 bridge->CommitUpdates();
473 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
478 IAccessible* node0_accessible =
node_delegate->GetNativeViewAccessible();
479 ASSERT_TRUE(node0_accessible !=
nullptr);
484 varchild.lVal = CHILDID_SELF;
489 ASSERT_EQ(node0_accessible->get_accRole(varchild, &varrole), S_OK);
490 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
493 long node0_child_count = 0;
494 ASSERT_EQ(node0_accessible->get_accChildCount(&node0_child_count), S_OK);
495 EXPECT_EQ(node0_child_count, 2);
500 IDispatch* node1_dispatch =
nullptr;
501 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node1_dispatch), S_OK);
502 ASSERT_TRUE(node1_dispatch !=
nullptr);
503 IAccessible* node1_accessible =
nullptr;
504 ASSERT_EQ(node1_dispatch->QueryInterface(
505 IID_IAccessible,
reinterpret_cast<void**
>(&node1_accessible)),
507 ASSERT_TRUE(node1_accessible !=
nullptr);
510 varchild.lVal = CHILDID_SELF;
511 BSTR bname =
nullptr;
512 ASSERT_EQ(node1_accessible->get_accName(varchild, &bname), S_OK);
513 std::string name(_com_util::ConvertBSTRToString(bname));
514 EXPECT_EQ(name,
"prefecture");
517 BSTR bvalue =
nullptr;
518 ASSERT_EQ(node1_accessible->get_accValue(varchild, &bvalue), S_OK);
519 std::string value(_com_util::ConvertBSTRToString(bvalue));
520 EXPECT_EQ(value,
"Kyoto");
525 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
526 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
529 IDispatch* parent_dispatch;
530 node1_accessible->get_accParent(&parent_dispatch);
531 IAccessible* parent_accessible;
533 parent_dispatch->QueryInterface(
534 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
536 EXPECT_EQ(parent_accessible, node0_accessible);
541 IDispatch* node2_dispatch =
nullptr;
542 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
543 ASSERT_TRUE(node2_dispatch !=
nullptr);
544 IAccessible* node2_accessible =
nullptr;
545 ASSERT_EQ(node2_dispatch->QueryInterface(
546 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
548 ASSERT_TRUE(node2_accessible !=
nullptr);
552 long node2_child_count = 0;
553 ASSERT_EQ(node2_accessible->get_accChildCount(&node2_child_count), S_OK);
554 EXPECT_EQ(node2_child_count, 1);
557 varchild.lVal = CHILDID_SELF;
560 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
561 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
564 IDispatch* parent_dispatch;
565 node2_accessible->get_accParent(&parent_dispatch);
566 IAccessible* parent_accessible;
568 parent_dispatch->QueryInterface(
569 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
571 EXPECT_EQ(parent_accessible, node0_accessible);
577 IDispatch* node3_dispatch =
nullptr;
578 ASSERT_EQ(node2_accessible->get_accChild(varchild, &node3_dispatch), S_OK);
579 ASSERT_TRUE(node3_dispatch !=
nullptr);
580 IAccessible* node3_accessible =
nullptr;
581 ASSERT_EQ(node3_dispatch->QueryInterface(
582 IID_IAccessible,
reinterpret_cast<void**
>(&node3_accessible)),
584 ASSERT_TRUE(node3_accessible !=
nullptr);
587 varchild.lVal = CHILDID_SELF;
588 BSTR bname =
nullptr;
589 ASSERT_EQ(node3_accessible->get_accName(varchild, &bname), S_OK);
590 std::string name(_com_util::ConvertBSTRToString(bname));
591 EXPECT_EQ(name,
"city");
594 BSTR bvalue =
nullptr;
595 ASSERT_EQ(node3_accessible->get_accValue(varchild, &bvalue), S_OK);
596 std::string value(_com_util::ConvertBSTRToString(bvalue));
597 EXPECT_EQ(value,
"Uji");
602 ASSERT_EQ(node3_accessible->get_accRole(varchild, &varrole), S_OK);
603 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
606 IDispatch* parent_dispatch;
607 node3_accessible->get_accParent(&parent_dispatch);
608 IAccessible* parent_accessible;
610 parent_dispatch->QueryInterface(
611 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
613 EXPECT_EQ(parent_accessible, node2_accessible);
626 TEST(FlutterWindowsViewTest, NonZeroSemanticsRoot) {
627 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
628 EngineModifier modifier(engine.get());
629 modifier.embedder_api().UpdateSemanticsEnabled =
634 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
635 std::make_unique<NiceMock<MockWindowBindingHandler>>());
638 view->OnUpdateSemanticsEnabled(
true);
640 auto bridge = view->accessibility_bridge().lock();
644 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
645 std::vector<int32_t> node1_children{2};
646 node1.child_count = node1_children.size();
647 node1.children_in_traversal_order = node1_children.data();
648 node1.children_in_hit_test_order = node1_children.data();
650 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
651 node2.label =
"prefecture";
652 node2.value =
"Kyoto";
654 bridge->AddFlutterSemanticsNodeUpdate(node1);
655 bridge->AddFlutterSemanticsNodeUpdate(node2);
656 bridge->CommitUpdates();
659 auto root_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
660 ASSERT_TRUE(root_delegate);
661 EXPECT_EQ(root_delegate->GetChildCount(), 1);
664 auto child_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
665 ASSERT_TRUE(child_delegate);
666 EXPECT_EQ(child_delegate->GetChildCount(), 0);
669 auto fake_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
670 ASSERT_FALSE(fake_delegate);
673 IAccessible* node1_accessible = root_delegate->GetNativeViewAccessible();
674 ASSERT_TRUE(node1_accessible !=
nullptr);
679 varchild.lVal = CHILDID_SELF;
684 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
685 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
688 long node1_child_count = 0;
689 ASSERT_EQ(node1_accessible->get_accChildCount(&node1_child_count), S_OK);
690 EXPECT_EQ(node1_child_count, 1);
695 IDispatch* node2_dispatch =
nullptr;
696 ASSERT_EQ(node1_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
697 ASSERT_TRUE(node2_dispatch !=
nullptr);
698 IAccessible* node2_accessible =
nullptr;
699 ASSERT_EQ(node2_dispatch->QueryInterface(
700 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
702 ASSERT_TRUE(node2_accessible !=
nullptr);
705 varchild.lVal = CHILDID_SELF;
706 BSTR bname =
nullptr;
707 ASSERT_EQ(node2_accessible->get_accName(varchild, &bname), S_OK);
708 std::string name(_com_util::ConvertBSTRToString(bname));
709 EXPECT_EQ(name,
"prefecture");
712 BSTR bvalue =
nullptr;
713 ASSERT_EQ(node2_accessible->get_accValue(varchild, &bvalue), S_OK);
714 std::string value(_com_util::ConvertBSTRToString(bvalue));
715 EXPECT_EQ(value,
"Kyoto");
720 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
721 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
724 IDispatch* parent_dispatch;
725 node2_accessible->get_accParent(&parent_dispatch);
726 IAccessible* parent_accessible;
728 parent_dispatch->QueryInterface(
729 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
731 EXPECT_EQ(parent_accessible, node1_accessible);
752 TEST(FlutterWindowsViewTest, AccessibilityHitTesting) {
753 constexpr FlutterTransformation kIdentityTransform = {1, 0, 0,
757 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
758 EngineModifier modifier(engine.get());
759 modifier.embedder_api().UpdateSemanticsEnabled =
764 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
765 std::make_unique<NiceMock<MockWindowBindingHandler>>());
768 view->OnUpdateSemanticsEnabled(
true);
770 auto bridge = view->accessibility_bridge().lock();
774 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
775 std::vector<int32_t> node0_children{1, 2};
776 node0.rect = {0, 0, 500, 500};
777 node0.transform = kIdentityTransform;
778 node0.child_count = node0_children.size();
779 node0.children_in_traversal_order = node0_children.data();
780 node0.children_in_hit_test_order = node0_children.data();
783 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
784 node1.rect = {0, 0, 250, 500};
785 node1.transform = kIdentityTransform;
786 node1.label =
"prefecture";
787 node1.value =
"Kyoto";
790 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
791 std::vector<int32_t> node2_children{3};
792 node2.rect = {0, 0, 250, 500};
793 node2.transform = {1, 0, 250, 0, 1, 0, 0, 0, 1};
794 node2.child_count = node2_children.size();
795 node2.children_in_traversal_order = node2_children.data();
796 node2.children_in_hit_test_order = node2_children.data();
799 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
800 node3.rect = {0, 0, 250, 250};
801 node3.transform = {1, 0, 0, 0, 1, 250, 0, 0, 1};
802 node3.label =
"city";
805 bridge->AddFlutterSemanticsNodeUpdate(node0);
806 bridge->AddFlutterSemanticsNodeUpdate(node1);
807 bridge->AddFlutterSemanticsNodeUpdate(node2);
808 bridge->AddFlutterSemanticsNodeUpdate(node3);
809 bridge->CommitUpdates();
812 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
813 ASSERT_TRUE(node0_delegate);
814 auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
815 ASSERT_TRUE(node1_delegate);
816 auto node2_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
817 ASSERT_TRUE(node2_delegate);
818 auto node3_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(3).lock();
819 ASSERT_TRUE(node3_delegate);
822 IAccessible* node0_accessible = node0_delegate->GetNativeViewAccessible();
823 ASSERT_TRUE(node0_accessible !=
nullptr);
827 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(150, 150, &varchild)));
828 EXPECT_EQ(varchild.vt, VT_DISPATCH);
829 EXPECT_EQ(varchild.pdispVal, node1_delegate->GetNativeViewAccessible());
833 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 150, &varchild)));
834 EXPECT_EQ(varchild.vt, VT_DISPATCH);
835 EXPECT_EQ(varchild.pdispVal, node2_delegate->GetNativeViewAccessible());
839 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 450, &varchild)));
840 EXPECT_EQ(varchild.vt, VT_DISPATCH);
841 EXPECT_EQ(varchild.pdispVal, node3_delegate->GetNativeViewAccessible());
844 TEST(FlutterWindowsViewTest, WindowResizeTests) {
845 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
846 std::unique_ptr<FlutterWindowsEngine> engine =
847 GetTestEngine(windows_proc_table);
849 EngineModifier engine_modifier{engine.get()};
850 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
851 PostRenderThreadTask,
857 auto egl_manager = std::make_unique<egl::MockManager>();
858 auto surface = std::make_unique<egl::MockWindowSurface>();
859 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
860 egl::MockContext render_context;
862 auto surface_ptr = surface.get();
863 auto resized_surface_ptr = resized_surface.get();
866 EXPECT_CALL(*egl_manager, CreateWindowSurface)
867 .WillOnce(Return(std::move(surface)));
868 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
869 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
870 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
871 EXPECT_CALL(*egl_manager, render_context).WillOnce(Return(&render_context));
872 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
875 EXPECT_CALL(*surface_ptr, Destroy).WillOnce(Return(
true));
876 EXPECT_CALL(*egl_manager.get(),
877 CreateWindowSurface(_, 500, 500))
878 .WillOnce(Return(std::move((resized_surface))));
879 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
880 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
881 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
883 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
885 engine_modifier.SetEGLManager(std::move(egl_manager));
887 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
888 std::make_unique<NiceMock<MockWindowBindingHandler>>());
890 fml::AutoResetWaitableEvent metrics_sent_latch;
891 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
892 SendWindowMetricsEvent,
893 ([&metrics_sent_latch](
auto engine,
894 const FlutterWindowMetricsEvent* event) {
895 metrics_sent_latch.Signal();
899 fml::AutoResetWaitableEvent resized_latch;
900 std::thread([&resized_latch, &view]() {
903 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
904 resized_latch.Signal();
908 metrics_sent_latch.Wait();
911 ASSERT_TRUE(view->OnFrameGenerated(500, 500));
912 view->OnFramePresented();
913 resized_latch.Wait();
917 TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) {
918 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
919 std::unique_ptr<FlutterWindowsEngine> engine =
920 GetTestEngine(windows_proc_table);
922 EngineModifier engine_modifier{engine.get()};
923 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
924 PostRenderThreadTask,
930 auto egl_manager = std::make_unique<egl::MockManager>();
931 auto surface = std::make_unique<egl::MockWindowSurface>();
932 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
933 auto resized_surface_ptr = resized_surface.get();
935 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
936 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
938 EXPECT_CALL(*egl_manager.get(),
939 CreateWindowSurface(_, 500, 500))
940 .WillOnce(Return(std::move((resized_surface))));
941 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
942 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
943 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
945 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
947 fml::AutoResetWaitableEvent metrics_sent_latch;
948 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
949 SendWindowMetricsEvent,
950 ([&metrics_sent_latch](
auto engine,
951 const FlutterWindowMetricsEvent* event) {
952 metrics_sent_latch.Signal();
956 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
957 std::make_unique<NiceMock<MockWindowBindingHandler>>());
959 ViewModifier view_modifier{view.get()};
960 engine_modifier.SetEGLManager(std::move(egl_manager));
961 view_modifier.SetSurface(std::move(surface));
963 fml::AutoResetWaitableEvent resized_latch;
964 std::thread([&resized_latch, &view]() {
967 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
968 resized_latch.Signal();
972 metrics_sent_latch.Wait();
975 view->OnEmptyFrameGenerated();
976 view->OnFramePresented();
977 resized_latch.Wait();
983 TEST(FlutterWindowsViewTest, WindowResizeRace) {
984 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
986 EngineModifier engine_modifier(engine.get());
987 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
988 PostRenderThreadTask,
994 auto egl_manager = std::make_unique<egl::MockManager>();
995 auto surface = std::make_unique<egl::MockWindowSurface>();
997 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
998 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
1000 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1001 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1003 ViewModifier view_modifier{view.get()};
1004 engine_modifier.SetEGLManager(std::move(egl_manager));
1005 view_modifier.SetSurface(std::move(surface));
1008 ASSERT_TRUE(view->OnFrameGenerated(100, 100));
1012 fml::AutoResetWaitableEvent resized_latch;
1013 std::thread([&resized_latch, &view]() {
1015 EXPECT_FALSE(view->OnWindowSizeChanged(500, 500));
1016 resized_latch.Signal();
1020 resized_latch.Wait();
1025 view->OnFramePresented();
1030 TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) {
1031 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1033 EngineModifier engine_modifier(engine.get());
1034 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
1035 PostRenderThreadTask,
1041 auto egl_manager = std::make_unique<egl::MockManager>();
1042 auto surface = std::make_unique<egl::MockWindowSurface>();
1044 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1045 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
false));
1046 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
false));
1048 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1049 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1051 ViewModifier view_modifier{view.get()};
1052 engine_modifier.SetEGLManager(std::move(egl_manager));
1053 view_modifier.SetSurface(std::move(surface));
1055 auto metrics_sent =
false;
1056 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1057 SendWindowMetricsEvent,
1058 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1059 metrics_sent =
true;
1063 view->OnWindowSizeChanged(500, 500);
1068 TEST(FlutterWindowsViewTest, WindowResizeWithoutSurface) {
1069 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1070 EngineModifier modifier(engine.get());
1072 auto egl_manager = std::make_unique<egl::MockManager>();
1074 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1076 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1077 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1079 modifier.SetEGLManager(std::move(egl_manager));
1081 auto metrics_sent =
false;
1082 modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1083 SendWindowMetricsEvent,
1084 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1085 metrics_sent =
true;
1089 view->OnWindowSizeChanged(500, 500);
1092 TEST(FlutterWindowsViewTest, WindowRepaintTests) {
1093 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1094 EngineModifier modifier(engine.get());
1097 std::make_unique<flutter::FlutterWindow>(100, 100)};
1099 bool schedule_frame_called =
false;
1100 modifier.embedder_api().ScheduleFrame =
1101 MOCK_ENGINE_PROC(ScheduleFrame, ([&schedule_frame_called](
auto engine) {
1102 schedule_frame_called =
true;
1106 view.OnWindowRepaint();
1107 EXPECT_TRUE(schedule_frame_called);
1116 TEST(FlutterWindowsViewTest, CheckboxNativeState) {
1117 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1118 EngineModifier modifier(engine.get());
1119 modifier.embedder_api().UpdateSemanticsEnabled =
1120 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1124 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1125 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1128 view->OnUpdateSemanticsEnabled(
true);
1130 auto bridge = view->accessibility_bridge().lock();
1131 ASSERT_TRUE(bridge);
1133 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1135 root.label =
"root";
1138 root.increased_value =
"";
1139 root.decreased_value =
"";
1140 root.child_count = 0;
1141 root.custom_accessibility_actions_count = 0;
1142 root.flags =
static_cast<FlutterSemanticsFlag
>(
1143 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
1144 FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked);
1145 bridge->AddFlutterSemanticsNodeUpdate(root);
1147 bridge->CommitUpdates();
1150 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1151 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1152 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1153 ax::mojom::CheckedState::kTrue);
1156 IAccessible* native_view = root_node->GetNativeViewAccessible();
1157 ASSERT_TRUE(native_view !=
nullptr);
1160 VARIANT varchild = {};
1161 varchild.vt = VT_I4;
1164 varchild.lVal = CHILDID_SELF;
1165 VARIANT native_state = {};
1166 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1167 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1170 IRawElementProviderSimple* uia_node;
1171 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1172 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1173 UIA_ToggleToggleStatePropertyId, &native_state)));
1174 EXPECT_EQ(native_state.lVal, ToggleState_On);
1176 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1177 UIA_AriaPropertiesPropertyId, &native_state)));
1178 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=true"),
nullptr);
1182 root.flags =
static_cast<FlutterSemanticsFlag
>(
1183 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState);
1184 bridge->AddFlutterSemanticsNodeUpdate(root);
1185 bridge->CommitUpdates();
1188 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1189 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1190 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1191 ax::mojom::CheckedState::kFalse);
1194 IAccessible* native_view = root_node->GetNativeViewAccessible();
1195 ASSERT_TRUE(native_view !=
nullptr);
1198 VARIANT varchild = {};
1199 varchild.vt = VT_I4;
1202 varchild.lVal = CHILDID_SELF;
1203 VARIANT native_state = {};
1204 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1205 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1208 IRawElementProviderSimple* uia_node;
1209 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1210 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1211 UIA_ToggleToggleStatePropertyId, &native_state)));
1212 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1214 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1215 UIA_AriaPropertiesPropertyId, &native_state)));
1216 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=false"),
nullptr);
1220 root.flags =
static_cast<FlutterSemanticsFlag
>(
1221 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
1222 FlutterSemanticsFlag::kFlutterSemanticsFlagIsCheckStateMixed);
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::kMixed);
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_TRUE(native_state.lVal & STATE_SYSTEM_MIXED);
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_Indeterminate);
1253 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1254 UIA_AriaPropertiesPropertyId, &native_state)));
1255 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=mixed"),
nullptr);
1260 TEST(FlutterWindowsViewTest, SwitchNativeState) {
1261 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1262 EngineModifier modifier(engine.get());
1263 modifier.embedder_api().UpdateSemanticsEnabled =
1264 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1268 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1269 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1272 view->OnUpdateSemanticsEnabled(
true);
1274 auto bridge = view->accessibility_bridge().lock();
1275 ASSERT_TRUE(bridge);
1277 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1279 root.label =
"root";
1282 root.increased_value =
"";
1283 root.decreased_value =
"";
1284 root.child_count = 0;
1285 root.custom_accessibility_actions_count = 0;
1286 root.flags =
static_cast<FlutterSemanticsFlag
>(
1287 FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState |
1288 FlutterSemanticsFlag::kFlutterSemanticsFlagIsToggled);
1289 bridge->AddFlutterSemanticsNodeUpdate(root);
1291 bridge->CommitUpdates();
1294 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1295 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1296 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1297 ax::mojom::CheckedState::kTrue);
1300 IAccessible* native_view = root_node->GetNativeViewAccessible();
1301 ASSERT_TRUE(native_view !=
nullptr);
1304 VARIANT varchild = {};
1305 varchild.vt = VT_I4;
1307 varchild.lVal = CHILDID_SELF;
1308 VARIANT varrole = {};
1311 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
1312 ASSERT_EQ(varrole.lVal, ROLE_SYSTEM_CHECKBUTTON);
1315 VARIANT native_state = {};
1316 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1317 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_PRESSED);
1318 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1321 IRawElementProviderSimple* uia_node;
1322 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1323 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
1325 EXPECT_EQ(varrole.lVal, UIA_ButtonControlTypeId);
1326 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1329 EXPECT_EQ(native_state.lVal, ToggleState_On);
1331 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1333 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=true"),
nullptr);
1337 root.flags =
static_cast<FlutterSemanticsFlag
>(
1338 FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState);
1339 bridge->AddFlutterSemanticsNodeUpdate(root);
1340 bridge->CommitUpdates();
1343 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1344 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1345 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1346 ax::mojom::CheckedState::kFalse);
1349 IAccessible* native_view = root_node->GetNativeViewAccessible();
1350 ASSERT_TRUE(native_view !=
nullptr);
1353 VARIANT varchild = {};
1354 varchild.vt = VT_I4;
1357 varchild.lVal = CHILDID_SELF;
1358 VARIANT native_state = {};
1359 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1360 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_PRESSED);
1361 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1364 IRawElementProviderSimple* uia_node;
1365 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1366 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1369 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1371 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1373 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=false"),
nullptr);
1377 TEST(FlutterWindowsViewTest, TooltipNodeData) {
1378 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1379 EngineModifier modifier(engine.get());
1380 modifier.embedder_api().UpdateSemanticsEnabled =
1381 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1385 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1386 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1389 view->OnUpdateSemanticsEnabled(
true);
1391 auto bridge = view->accessibility_bridge().lock();
1392 ASSERT_TRUE(bridge);
1394 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1396 root.label =
"root";
1399 root.increased_value =
"";
1400 root.decreased_value =
"";
1401 root.tooltip =
"tooltip";
1402 root.child_count = 0;
1403 root.custom_accessibility_actions_count = 0;
1404 root.flags =
static_cast<FlutterSemanticsFlag
>(
1405 FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField);
1406 bridge->AddFlutterSemanticsNodeUpdate(root);
1408 bridge->CommitUpdates();
1409 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1410 std::string tooltip = root_node->GetData().GetStringAttribute(
1411 ax::mojom::StringAttribute::kTooltip);
1412 EXPECT_EQ(tooltip,
"tooltip");
1415 IAccessible* native_view = bridge->GetFlutterPlatformNodeDelegateFromID(0)
1417 ->GetNativeViewAccessible();
1418 VARIANT varchild = {.vt = VT_I4, .lVal = CHILDID_SELF};
1420 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
1421 EXPECT_NE(std::wcsstr(bname, L
"tooltip"),
nullptr);
1424 IRawElementProviderSimple* uia_node;
1425 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1427 ASSERT_EQ(uia_node->GetPropertyValue(UIA_HelpTextPropertyId, &varname), S_OK);
1428 std::string uia_tooltip = _com_util::ConvertBSTRToString(varname.bstrVal);
1429 EXPECT_EQ(uia_tooltip,
"tooltip");
1434 TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) {
1435 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1436 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1437 auto egl_manager = std::make_unique<egl::MockManager>();
1438 egl::MockContext render_context;
1439 auto surface = std::make_unique<egl::MockWindowSurface>();
1440 auto surface_ptr = surface.get();
1442 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1443 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1445 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1446 .WillOnce(Return(
true));
1448 EXPECT_CALL(*egl_manager.get(), render_context)
1449 .WillOnce(Return(&render_context));
1450 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1453 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1454 .WillOnce(Return(std::move(surface)));
1455 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1456 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1457 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1459 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1461 EngineModifier modifier{engine.get()};
1462 modifier.SetEGLManager(std::move(egl_manager));
1464 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1465 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1470 TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) {
1471 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1472 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1473 auto egl_manager = std::make_unique<egl::MockManager>();
1474 egl::MockContext render_context;
1475 auto surface = std::make_unique<egl::MockWindowSurface>();
1476 auto surface_ptr = surface.get();
1478 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1479 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1480 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1481 .WillOnce(Return(
false));
1483 EXPECT_CALL(*egl_manager.get(), render_context)
1484 .WillOnce(Return(&render_context));
1485 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1488 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1489 .WillOnce(Return(std::move(surface)));
1490 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1491 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1492 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1494 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1496 EngineModifier modifier{engine.get()};
1497 modifier.SetEGLManager(std::move(egl_manager));
1499 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1500 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1505 TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) {
1506 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1507 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1508 auto egl_manager = std::make_unique<egl::MockManager>();
1509 egl::MockContext render_context;
1510 auto surface = std::make_unique<egl::MockWindowSurface>();
1511 auto surface_ptr = surface.get();
1513 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1514 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1515 .WillOnce(Return(
true));
1517 EXPECT_CALL(*egl_manager.get(), render_context)
1518 .WillOnce(Return(&render_context));
1519 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1522 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1523 .WillOnce(Return(std::move(surface)));
1524 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1525 .WillOnce([](fml::closure
callback) {
1529 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1530 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1531 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1532 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1533 .WillOnce([](fml::closure
callback) {
1537 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1539 EngineModifier modifier{engine.get()};
1540 modifier.SetEGLManager(std::move(egl_manager));
1542 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1543 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1548 TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) {
1549 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1550 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1551 auto egl_manager = std::make_unique<egl::MockManager>();
1552 egl::MockContext render_context;
1553 auto surface = std::make_unique<egl::MockWindowSurface>();
1554 auto surface_ptr = surface.get();
1556 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1558 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1559 .WillOnce(Return(
false));
1561 EXPECT_CALL(*egl_manager.get(), render_context)
1562 .WillOnce(Return(&render_context));
1563 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1566 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1567 .WillOnce(Return(std::move(surface)));
1568 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1569 .WillOnce([](fml::closure
callback) {
1574 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1575 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1576 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1578 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1579 .WillOnce([](fml::closure
callback) {
1583 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1585 EngineModifier modifier{engine.get()};
1586 modifier.SetEGLManager(std::move(egl_manager));
1588 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1589 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1595 TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) {
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(*engine.get(), PostRasterThreadTask)
1606 .WillRepeatedly([](fml::closure
callback) {
1611 EXPECT_CALL(*egl_manager.get(), render_context)
1612 .WillRepeatedly(Return(&render_context));
1614 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
1615 EXPECT_CALL(*surface_ptr, MakeCurrent).WillRepeatedly(Return(
true));
1616 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1617 EXPECT_CALL(render_context, ClearCurrent).WillRepeatedly(Return(
true));
1622 std::unique_ptr<FlutterWindowsView> view;
1624 EXPECT_CALL(*egl_manager, CreateWindowSurface)
1625 .WillOnce(Return(std::move(surface)));
1626 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1627 .WillOnce(Return(
true));
1628 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
1630 EngineModifier engine_modifier{engine.get()};
1631 engine_modifier.SetEGLManager(std::move(egl_manager));
1633 view = engine->CreateView(
1634 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1639 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1640 .WillOnce(Return(
false));
1641 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1643 engine->OnDwmCompositionChanged();
1648 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1649 .WillOnce(Return(
true));
1650 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1652 engine->OnDwmCompositionChanged();