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, KeyEventCallback) {
310 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
312 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
313 std::make_unique<NiceMock<MockWindowBindingHandler>>());
317 MOCK_METHOD(
void, Call, ());
320 NiceMock<MockCallback> callback_with_valid_view;
321 NiceMock<MockCallback> callback_with_invalid_view;
323 auto trigger_key_event = [&](NiceMock<MockCallback>&
callback) {
328 EXPECT_CALL(callback_with_valid_view, Call()).Times(1);
329 EXPECT_CALL(callback_with_invalid_view, Call()).Times(0);
331 trigger_key_event(callback_with_valid_view);
332 engine->RemoveView(view->view_id());
333 trigger_key_event(callback_with_invalid_view);
335 key_event_logs.clear();
338 TEST(FlutterWindowsViewTest, EnableSemantics) {
339 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
340 EngineModifier modifier(engine.get());
342 bool semantics_enabled =
false;
343 modifier.embedder_api().UpdateSemanticsEnabled = MOCK_ENGINE_PROC(
344 UpdateSemanticsEnabled,
345 [&semantics_enabled](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
347 semantics_enabled = enabled;
351 auto window_binding_handler =
352 std::make_unique<NiceMock<MockWindowBindingHandler>>();
353 std::unique_ptr<FlutterWindowsView> view =
354 engine->CreateView(std::move(window_binding_handler));
356 view->OnUpdateSemanticsEnabled(
true);
357 EXPECT_TRUE(semantics_enabled);
360 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdate) {
361 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
362 EngineModifier modifier(engine.get());
363 modifier.embedder_api().UpdateSemanticsEnabled =
368 auto window_binding_handler =
369 std::make_unique<NiceMock<MockWindowBindingHandler>>();
370 std::unique_ptr<FlutterWindowsView> view =
371 engine->CreateView(std::move(window_binding_handler));
374 view->OnUpdateSemanticsEnabled(
true);
376 auto bridge = view->accessibility_bridge().lock();
380 FlutterSemanticsNode2 node{
sizeof(FlutterSemanticsNode2), 0};
382 node.value =
"value";
383 node.platform_view_id = -1;
384 bridge->AddFlutterSemanticsNodeUpdate(node);
385 bridge->CommitUpdates();
388 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
393 IAccessible* native_view =
node_delegate->GetNativeViewAccessible();
394 ASSERT_TRUE(native_view !=
nullptr);
399 varchild.lVal = CHILDID_SELF;
402 BSTR bname =
nullptr;
403 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
404 std::string name(_com_util::ConvertBSTRToString(bname));
405 EXPECT_EQ(name,
"name");
408 BSTR bvalue =
nullptr;
409 ASSERT_EQ(native_view->get_accValue(varchild, &bvalue), S_OK);
410 std::string value(_com_util::ConvertBSTRToString(bvalue));
411 EXPECT_EQ(value,
"value");
416 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
417 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
420 IRawElementProviderSimple* uia_view;
421 native_view->QueryInterface(IID_PPV_ARGS(&uia_view));
422 ASSERT_TRUE(uia_view !=
nullptr);
426 ASSERT_EQ(uia_view->GetPropertyValue(UIA_NamePropertyId, &varname), S_OK);
427 EXPECT_EQ(varname.vt, VT_BSTR);
428 name = _com_util::ConvertBSTRToString(varname.bstrVal);
429 EXPECT_EQ(name,
"name");
433 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue),
435 EXPECT_EQ(varvalue.vt, VT_BSTR);
436 value = _com_util::ConvertBSTRToString(varvalue.bstrVal);
437 EXPECT_EQ(value,
"value");
441 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
443 EXPECT_EQ(varrole.vt, VT_I4);
444 EXPECT_EQ(varrole.lVal, UIA_TextControlTypeId);
459 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdateWithChildren) {
460 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
461 EngineModifier modifier(engine.get());
462 modifier.embedder_api().UpdateSemanticsEnabled =
467 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
468 std::make_unique<NiceMock<MockWindowBindingHandler>>());
471 view->OnUpdateSemanticsEnabled(
true);
473 auto bridge = view->accessibility_bridge().lock();
477 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
478 std::vector<int32_t> node0_children{1, 2};
479 node0.child_count = node0_children.size();
480 node0.children_in_traversal_order = node0_children.data();
481 node0.children_in_hit_test_order = node0_children.data();
483 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
484 node1.label =
"prefecture";
485 node1.value =
"Kyoto";
486 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
487 std::vector<int32_t> node2_children{3};
488 node2.child_count = node2_children.size();
489 node2.children_in_traversal_order = node2_children.data();
490 node2.children_in_hit_test_order = node2_children.data();
491 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
492 node3.label =
"city";
495 bridge->AddFlutterSemanticsNodeUpdate(node0);
496 bridge->AddFlutterSemanticsNodeUpdate(node1);
497 bridge->AddFlutterSemanticsNodeUpdate(node2);
498 bridge->AddFlutterSemanticsNodeUpdate(node3);
499 bridge->CommitUpdates();
502 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
507 IAccessible* node0_accessible =
node_delegate->GetNativeViewAccessible();
508 ASSERT_TRUE(node0_accessible !=
nullptr);
513 varchild.lVal = CHILDID_SELF;
518 ASSERT_EQ(node0_accessible->get_accRole(varchild, &varrole), S_OK);
519 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
522 long node0_child_count = 0;
523 ASSERT_EQ(node0_accessible->get_accChildCount(&node0_child_count), S_OK);
524 EXPECT_EQ(node0_child_count, 2);
529 IDispatch* node1_dispatch =
nullptr;
530 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node1_dispatch), S_OK);
531 ASSERT_TRUE(node1_dispatch !=
nullptr);
532 IAccessible* node1_accessible =
nullptr;
533 ASSERT_EQ(node1_dispatch->QueryInterface(
534 IID_IAccessible,
reinterpret_cast<void**
>(&node1_accessible)),
536 ASSERT_TRUE(node1_accessible !=
nullptr);
539 varchild.lVal = CHILDID_SELF;
540 BSTR bname =
nullptr;
541 ASSERT_EQ(node1_accessible->get_accName(varchild, &bname), S_OK);
542 std::string name(_com_util::ConvertBSTRToString(bname));
543 EXPECT_EQ(name,
"prefecture");
546 BSTR bvalue =
nullptr;
547 ASSERT_EQ(node1_accessible->get_accValue(varchild, &bvalue), S_OK);
548 std::string value(_com_util::ConvertBSTRToString(bvalue));
549 EXPECT_EQ(value,
"Kyoto");
554 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
555 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
558 IDispatch* parent_dispatch;
559 node1_accessible->get_accParent(&parent_dispatch);
560 IAccessible* parent_accessible;
562 parent_dispatch->QueryInterface(
563 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
565 EXPECT_EQ(parent_accessible, node0_accessible);
570 IDispatch* node2_dispatch =
nullptr;
571 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
572 ASSERT_TRUE(node2_dispatch !=
nullptr);
573 IAccessible* node2_accessible =
nullptr;
574 ASSERT_EQ(node2_dispatch->QueryInterface(
575 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
577 ASSERT_TRUE(node2_accessible !=
nullptr);
581 long node2_child_count = 0;
582 ASSERT_EQ(node2_accessible->get_accChildCount(&node2_child_count), S_OK);
583 EXPECT_EQ(node2_child_count, 1);
586 varchild.lVal = CHILDID_SELF;
589 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
590 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
593 IDispatch* parent_dispatch;
594 node2_accessible->get_accParent(&parent_dispatch);
595 IAccessible* parent_accessible;
597 parent_dispatch->QueryInterface(
598 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
600 EXPECT_EQ(parent_accessible, node0_accessible);
606 IDispatch* node3_dispatch =
nullptr;
607 ASSERT_EQ(node2_accessible->get_accChild(varchild, &node3_dispatch), S_OK);
608 ASSERT_TRUE(node3_dispatch !=
nullptr);
609 IAccessible* node3_accessible =
nullptr;
610 ASSERT_EQ(node3_dispatch->QueryInterface(
611 IID_IAccessible,
reinterpret_cast<void**
>(&node3_accessible)),
613 ASSERT_TRUE(node3_accessible !=
nullptr);
616 varchild.lVal = CHILDID_SELF;
617 BSTR bname =
nullptr;
618 ASSERT_EQ(node3_accessible->get_accName(varchild, &bname), S_OK);
619 std::string name(_com_util::ConvertBSTRToString(bname));
620 EXPECT_EQ(name,
"city");
623 BSTR bvalue =
nullptr;
624 ASSERT_EQ(node3_accessible->get_accValue(varchild, &bvalue), S_OK);
625 std::string value(_com_util::ConvertBSTRToString(bvalue));
626 EXPECT_EQ(value,
"Uji");
631 ASSERT_EQ(node3_accessible->get_accRole(varchild, &varrole), S_OK);
632 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
635 IDispatch* parent_dispatch;
636 node3_accessible->get_accParent(&parent_dispatch);
637 IAccessible* parent_accessible;
639 parent_dispatch->QueryInterface(
640 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
642 EXPECT_EQ(parent_accessible, node2_accessible);
655 TEST(FlutterWindowsViewTest, NonZeroSemanticsRoot) {
656 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
657 EngineModifier modifier(engine.get());
658 modifier.embedder_api().UpdateSemanticsEnabled =
663 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
664 std::make_unique<NiceMock<MockWindowBindingHandler>>());
667 view->OnUpdateSemanticsEnabled(
true);
669 auto bridge = view->accessibility_bridge().lock();
673 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
674 std::vector<int32_t> node1_children{2};
675 node1.child_count = node1_children.size();
676 node1.children_in_traversal_order = node1_children.data();
677 node1.children_in_hit_test_order = node1_children.data();
679 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
680 node2.label =
"prefecture";
681 node2.value =
"Kyoto";
683 bridge->AddFlutterSemanticsNodeUpdate(node1);
684 bridge->AddFlutterSemanticsNodeUpdate(node2);
685 bridge->CommitUpdates();
688 auto root_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
689 ASSERT_TRUE(root_delegate);
690 EXPECT_EQ(root_delegate->GetChildCount(), 1);
693 auto child_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
694 ASSERT_TRUE(child_delegate);
695 EXPECT_EQ(child_delegate->GetChildCount(), 0);
698 auto fake_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
699 ASSERT_FALSE(fake_delegate);
702 IAccessible* node1_accessible = root_delegate->GetNativeViewAccessible();
703 ASSERT_TRUE(node1_accessible !=
nullptr);
708 varchild.lVal = CHILDID_SELF;
713 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
714 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
717 long node1_child_count = 0;
718 ASSERT_EQ(node1_accessible->get_accChildCount(&node1_child_count), S_OK);
719 EXPECT_EQ(node1_child_count, 1);
724 IDispatch* node2_dispatch =
nullptr;
725 ASSERT_EQ(node1_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
726 ASSERT_TRUE(node2_dispatch !=
nullptr);
727 IAccessible* node2_accessible =
nullptr;
728 ASSERT_EQ(node2_dispatch->QueryInterface(
729 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
731 ASSERT_TRUE(node2_accessible !=
nullptr);
734 varchild.lVal = CHILDID_SELF;
735 BSTR bname =
nullptr;
736 ASSERT_EQ(node2_accessible->get_accName(varchild, &bname), S_OK);
737 std::string name(_com_util::ConvertBSTRToString(bname));
738 EXPECT_EQ(name,
"prefecture");
741 BSTR bvalue =
nullptr;
742 ASSERT_EQ(node2_accessible->get_accValue(varchild, &bvalue), S_OK);
743 std::string value(_com_util::ConvertBSTRToString(bvalue));
744 EXPECT_EQ(value,
"Kyoto");
749 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
750 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
753 IDispatch* parent_dispatch;
754 node2_accessible->get_accParent(&parent_dispatch);
755 IAccessible* parent_accessible;
757 parent_dispatch->QueryInterface(
758 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
760 EXPECT_EQ(parent_accessible, node1_accessible);
781 TEST(FlutterWindowsViewTest, AccessibilityHitTesting) {
782 constexpr FlutterTransformation kIdentityTransform = {1, 0, 0,
786 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
787 EngineModifier modifier(engine.get());
788 modifier.embedder_api().UpdateSemanticsEnabled =
793 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
794 std::make_unique<NiceMock<MockWindowBindingHandler>>());
797 view->OnUpdateSemanticsEnabled(
true);
799 auto bridge = view->accessibility_bridge().lock();
803 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
804 std::vector<int32_t> node0_children{1, 2};
805 node0.rect = {0, 0, 500, 500};
806 node0.transform = kIdentityTransform;
807 node0.child_count = node0_children.size();
808 node0.children_in_traversal_order = node0_children.data();
809 node0.children_in_hit_test_order = node0_children.data();
812 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
813 node1.rect = {0, 0, 250, 500};
814 node1.transform = kIdentityTransform;
815 node1.label =
"prefecture";
816 node1.value =
"Kyoto";
819 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
820 std::vector<int32_t> node2_children{3};
821 node2.rect = {0, 0, 250, 500};
822 node2.transform = {1, 0, 250, 0, 1, 0, 0, 0, 1};
823 node2.child_count = node2_children.size();
824 node2.children_in_traversal_order = node2_children.data();
825 node2.children_in_hit_test_order = node2_children.data();
828 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
829 node3.rect = {0, 0, 250, 250};
830 node3.transform = {1, 0, 0, 0, 1, 250, 0, 0, 1};
831 node3.label =
"city";
834 bridge->AddFlutterSemanticsNodeUpdate(node0);
835 bridge->AddFlutterSemanticsNodeUpdate(node1);
836 bridge->AddFlutterSemanticsNodeUpdate(node2);
837 bridge->AddFlutterSemanticsNodeUpdate(node3);
838 bridge->CommitUpdates();
841 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
842 ASSERT_TRUE(node0_delegate);
843 auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
844 ASSERT_TRUE(node1_delegate);
845 auto node2_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
846 ASSERT_TRUE(node2_delegate);
847 auto node3_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(3).lock();
848 ASSERT_TRUE(node3_delegate);
851 IAccessible* node0_accessible = node0_delegate->GetNativeViewAccessible();
852 ASSERT_TRUE(node0_accessible !=
nullptr);
856 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(150, 150, &varchild)));
857 EXPECT_EQ(varchild.vt, VT_DISPATCH);
858 EXPECT_EQ(varchild.pdispVal, node1_delegate->GetNativeViewAccessible());
862 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 150, &varchild)));
863 EXPECT_EQ(varchild.vt, VT_DISPATCH);
864 EXPECT_EQ(varchild.pdispVal, node2_delegate->GetNativeViewAccessible());
868 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 450, &varchild)));
869 EXPECT_EQ(varchild.vt, VT_DISPATCH);
870 EXPECT_EQ(varchild.pdispVal, node3_delegate->GetNativeViewAccessible());
873 TEST(FlutterWindowsViewTest, WindowResizeTests) {
874 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
875 std::unique_ptr<FlutterWindowsEngine> engine =
876 GetTestEngine(windows_proc_table);
878 EngineModifier engine_modifier{engine.get()};
879 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
880 PostRenderThreadTask,
886 auto egl_manager = std::make_unique<egl::MockManager>();
887 auto surface = std::make_unique<egl::MockWindowSurface>();
888 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
889 egl::MockContext render_context;
891 auto surface_ptr = surface.get();
892 auto resized_surface_ptr = resized_surface.get();
895 EXPECT_CALL(*egl_manager, CreateWindowSurface)
896 .WillOnce(Return(std::move(surface)));
897 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
898 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
899 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
900 EXPECT_CALL(*egl_manager, render_context).WillOnce(Return(&render_context));
901 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
904 EXPECT_CALL(*surface_ptr, Destroy).WillOnce(Return(
true));
905 EXPECT_CALL(*egl_manager.get(),
906 CreateWindowSurface(_, 500, 500))
907 .WillOnce(Return(std::move((resized_surface))));
908 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
909 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
910 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
912 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
914 engine_modifier.SetEGLManager(std::move(egl_manager));
916 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
917 std::make_unique<NiceMock<MockWindowBindingHandler>>());
919 fml::AutoResetWaitableEvent metrics_sent_latch;
920 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
921 SendWindowMetricsEvent,
922 ([&metrics_sent_latch](
auto engine,
923 const FlutterWindowMetricsEvent* event) {
924 metrics_sent_latch.Signal();
929 std::thread([&metrics_sent_latch, &view]() {
930 metrics_sent_latch.Wait();
932 EXPECT_TRUE(view->OnFrameGenerated(500, 500));
933 view->OnFramePresented();
939 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
943 TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) {
944 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
945 std::unique_ptr<FlutterWindowsEngine> engine =
946 GetTestEngine(windows_proc_table);
948 EngineModifier engine_modifier{engine.get()};
949 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
950 PostRenderThreadTask,
956 auto egl_manager = std::make_unique<egl::MockManager>();
957 auto surface = std::make_unique<egl::MockWindowSurface>();
958 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
959 auto resized_surface_ptr = resized_surface.get();
961 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
962 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
964 EXPECT_CALL(*egl_manager.get(),
965 CreateWindowSurface(_, 500, 500))
966 .WillOnce(Return(std::move((resized_surface))));
967 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
968 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
969 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
971 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
973 fml::AutoResetWaitableEvent metrics_sent_latch;
974 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
975 SendWindowMetricsEvent,
976 ([&metrics_sent_latch](
auto engine,
977 const FlutterWindowMetricsEvent* event) {
978 metrics_sent_latch.Signal();
982 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
983 std::make_unique<NiceMock<MockWindowBindingHandler>>());
985 ViewModifier view_modifier{view.get()};
986 engine_modifier.SetEGLManager(std::move(egl_manager));
987 view_modifier.SetSurface(std::move(surface));
990 std::thread([&metrics_sent_latch, &view]() {
991 metrics_sent_latch.Wait();
994 EXPECT_TRUE(view->OnEmptyFrameGenerated());
995 view->OnFramePresented();
1000 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
1006 TEST(FlutterWindowsViewTest, WindowResizeRace) {
1007 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1009 EngineModifier engine_modifier(engine.get());
1010 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
1011 PostRenderThreadTask,
1017 auto egl_manager = std::make_unique<egl::MockManager>();
1018 auto surface = std::make_unique<egl::MockWindowSurface>();
1020 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
1021 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
1023 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1024 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1026 ViewModifier view_modifier{view.get()};
1027 engine_modifier.SetEGLManager(std::move(egl_manager));
1028 view_modifier.SetSurface(std::move(surface));
1031 ASSERT_TRUE(view->OnFrameGenerated(100, 100));
1035 EXPECT_FALSE(view->OnWindowSizeChanged(500, 500));
1040 view->OnFramePresented();
1045 TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) {
1046 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1048 EngineModifier engine_modifier(engine.get());
1049 engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC(
1050 PostRenderThreadTask,
1056 auto egl_manager = std::make_unique<egl::MockManager>();
1057 auto surface = std::make_unique<egl::MockWindowSurface>();
1059 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1060 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
false));
1061 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
false));
1063 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1064 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1066 ViewModifier view_modifier{view.get()};
1067 engine_modifier.SetEGLManager(std::move(egl_manager));
1068 view_modifier.SetSurface(std::move(surface));
1070 auto metrics_sent =
false;
1071 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1072 SendWindowMetricsEvent,
1073 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1074 metrics_sent =
true;
1078 view->OnWindowSizeChanged(500, 500);
1083 TEST(FlutterWindowsViewTest, WindowResizeWithoutSurface) {
1084 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1085 EngineModifier modifier(engine.get());
1087 auto egl_manager = std::make_unique<egl::MockManager>();
1089 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1091 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1092 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1094 modifier.SetEGLManager(std::move(egl_manager));
1096 auto metrics_sent =
false;
1097 modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1098 SendWindowMetricsEvent,
1099 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1100 metrics_sent =
true;
1104 view->OnWindowSizeChanged(500, 500);
1107 TEST(FlutterWindowsViewTest, WindowRepaintTests) {
1108 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1109 EngineModifier modifier(engine.get());
1112 std::make_unique<flutter::FlutterWindow>(100, 100)};
1114 bool schedule_frame_called =
false;
1115 modifier.embedder_api().ScheduleFrame =
1116 MOCK_ENGINE_PROC(ScheduleFrame, ([&schedule_frame_called](
auto engine) {
1117 schedule_frame_called =
true;
1121 view.OnWindowRepaint();
1122 EXPECT_TRUE(schedule_frame_called);
1131 TEST(FlutterWindowsViewTest, CheckboxNativeState) {
1132 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1133 EngineModifier modifier(engine.get());
1134 modifier.embedder_api().UpdateSemanticsEnabled =
1135 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1139 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1140 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1143 view->OnUpdateSemanticsEnabled(
true);
1145 auto bridge = view->accessibility_bridge().lock();
1146 ASSERT_TRUE(bridge);
1148 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1150 root.label =
"root";
1153 root.increased_value =
"";
1154 root.decreased_value =
"";
1155 root.child_count = 0;
1156 root.custom_accessibility_actions_count = 0;
1157 root.flags =
static_cast<FlutterSemanticsFlag
>(
1158 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
1159 FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked);
1160 bridge->AddFlutterSemanticsNodeUpdate(root);
1162 bridge->CommitUpdates();
1165 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1166 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1167 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1168 ax::mojom::CheckedState::kTrue);
1171 IAccessible* native_view = root_node->GetNativeViewAccessible();
1172 ASSERT_TRUE(native_view !=
nullptr);
1175 VARIANT varchild = {};
1176 varchild.vt = VT_I4;
1179 varchild.lVal = CHILDID_SELF;
1180 VARIANT native_state = {};
1181 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1182 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1185 IRawElementProviderSimple* uia_node;
1186 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1187 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1188 UIA_ToggleToggleStatePropertyId, &native_state)));
1189 EXPECT_EQ(native_state.lVal, ToggleState_On);
1191 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1192 UIA_AriaPropertiesPropertyId, &native_state)));
1193 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=true"),
nullptr);
1197 root.flags =
static_cast<FlutterSemanticsFlag
>(
1198 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState);
1199 bridge->AddFlutterSemanticsNodeUpdate(root);
1200 bridge->CommitUpdates();
1203 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1204 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1205 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1206 ax::mojom::CheckedState::kFalse);
1209 IAccessible* native_view = root_node->GetNativeViewAccessible();
1210 ASSERT_TRUE(native_view !=
nullptr);
1213 VARIANT varchild = {};
1214 varchild.vt = VT_I4;
1217 varchild.lVal = CHILDID_SELF;
1218 VARIANT native_state = {};
1219 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1220 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1223 IRawElementProviderSimple* uia_node;
1224 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1225 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1226 UIA_ToggleToggleStatePropertyId, &native_state)));
1227 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1229 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1230 UIA_AriaPropertiesPropertyId, &native_state)));
1231 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=false"),
nullptr);
1235 root.flags =
static_cast<FlutterSemanticsFlag
>(
1236 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
1237 FlutterSemanticsFlag::kFlutterSemanticsFlagIsCheckStateMixed);
1238 bridge->AddFlutterSemanticsNodeUpdate(root);
1239 bridge->CommitUpdates();
1242 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1243 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1244 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1245 ax::mojom::CheckedState::kMixed);
1248 IAccessible* native_view = root_node->GetNativeViewAccessible();
1249 ASSERT_TRUE(native_view !=
nullptr);
1252 VARIANT varchild = {};
1253 varchild.vt = VT_I4;
1256 varchild.lVal = CHILDID_SELF;
1257 VARIANT native_state = {};
1258 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1259 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_MIXED);
1262 IRawElementProviderSimple* uia_node;
1263 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1264 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1265 UIA_ToggleToggleStatePropertyId, &native_state)));
1266 EXPECT_EQ(native_state.lVal, ToggleState_Indeterminate);
1268 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1269 UIA_AriaPropertiesPropertyId, &native_state)));
1270 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=mixed"),
nullptr);
1275 TEST(FlutterWindowsViewTest, SwitchNativeState) {
1276 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1277 EngineModifier modifier(engine.get());
1278 modifier.embedder_api().UpdateSemanticsEnabled =
1279 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1283 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1284 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1287 view->OnUpdateSemanticsEnabled(
true);
1289 auto bridge = view->accessibility_bridge().lock();
1290 ASSERT_TRUE(bridge);
1292 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1294 root.label =
"root";
1297 root.increased_value =
"";
1298 root.decreased_value =
"";
1299 root.child_count = 0;
1300 root.custom_accessibility_actions_count = 0;
1301 root.flags =
static_cast<FlutterSemanticsFlag
>(
1302 FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState |
1303 FlutterSemanticsFlag::kFlutterSemanticsFlagIsToggled);
1304 bridge->AddFlutterSemanticsNodeUpdate(root);
1306 bridge->CommitUpdates();
1309 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1310 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1311 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1312 ax::mojom::CheckedState::kTrue);
1315 IAccessible* native_view = root_node->GetNativeViewAccessible();
1316 ASSERT_TRUE(native_view !=
nullptr);
1319 VARIANT varchild = {};
1320 varchild.vt = VT_I4;
1322 varchild.lVal = CHILDID_SELF;
1323 VARIANT varrole = {};
1326 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
1327 ASSERT_EQ(varrole.lVal, ROLE_SYSTEM_CHECKBUTTON);
1330 VARIANT native_state = {};
1331 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1332 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_PRESSED);
1333 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1336 IRawElementProviderSimple* uia_node;
1337 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1338 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
1340 EXPECT_EQ(varrole.lVal, UIA_ButtonControlTypeId);
1341 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1344 EXPECT_EQ(native_state.lVal, ToggleState_On);
1346 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1348 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=true"),
nullptr);
1352 root.flags =
static_cast<FlutterSemanticsFlag
>(
1353 FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState);
1354 bridge->AddFlutterSemanticsNodeUpdate(root);
1355 bridge->CommitUpdates();
1358 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1359 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1360 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1361 ax::mojom::CheckedState::kFalse);
1364 IAccessible* native_view = root_node->GetNativeViewAccessible();
1365 ASSERT_TRUE(native_view !=
nullptr);
1368 VARIANT varchild = {};
1369 varchild.vt = VT_I4;
1372 varchild.lVal = CHILDID_SELF;
1373 VARIANT native_state = {};
1374 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1375 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_PRESSED);
1376 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1379 IRawElementProviderSimple* uia_node;
1380 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1381 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1384 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1386 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1388 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=false"),
nullptr);
1392 TEST(FlutterWindowsViewTest, TooltipNodeData) {
1393 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1394 EngineModifier modifier(engine.get());
1395 modifier.embedder_api().UpdateSemanticsEnabled =
1396 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1400 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1401 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1404 view->OnUpdateSemanticsEnabled(
true);
1406 auto bridge = view->accessibility_bridge().lock();
1407 ASSERT_TRUE(bridge);
1409 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1411 root.label =
"root";
1414 root.increased_value =
"";
1415 root.decreased_value =
"";
1416 root.tooltip =
"tooltip";
1417 root.child_count = 0;
1418 root.custom_accessibility_actions_count = 0;
1419 root.flags =
static_cast<FlutterSemanticsFlag
>(
1420 FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField);
1421 bridge->AddFlutterSemanticsNodeUpdate(root);
1423 bridge->CommitUpdates();
1424 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1425 std::string tooltip = root_node->GetData().GetStringAttribute(
1426 ax::mojom::StringAttribute::kTooltip);
1427 EXPECT_EQ(tooltip,
"tooltip");
1430 IAccessible* native_view = bridge->GetFlutterPlatformNodeDelegateFromID(0)
1432 ->GetNativeViewAccessible();
1433 VARIANT varchild = {.vt = VT_I4, .lVal = CHILDID_SELF};
1435 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
1436 EXPECT_NE(std::wcsstr(bname, L
"tooltip"),
nullptr);
1439 IRawElementProviderSimple* uia_node;
1440 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1442 ASSERT_EQ(uia_node->GetPropertyValue(UIA_HelpTextPropertyId, &varname), S_OK);
1443 std::string uia_tooltip = _com_util::ConvertBSTRToString(varname.bstrVal);
1444 EXPECT_EQ(uia_tooltip,
"tooltip");
1449 TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) {
1450 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1451 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1452 auto egl_manager = std::make_unique<egl::MockManager>();
1453 egl::MockContext render_context;
1454 auto surface = std::make_unique<egl::MockWindowSurface>();
1455 auto surface_ptr = surface.get();
1457 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1458 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1460 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1461 .WillOnce(Return(
true));
1463 EXPECT_CALL(*egl_manager.get(), render_context)
1464 .WillOnce(Return(&render_context));
1465 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1468 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1469 .WillOnce(Return(std::move(surface)));
1470 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1471 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1472 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1474 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1476 EngineModifier modifier{engine.get()};
1477 modifier.SetEGLManager(std::move(egl_manager));
1479 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1480 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1485 TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) {
1486 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1487 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1488 auto egl_manager = std::make_unique<egl::MockManager>();
1489 egl::MockContext render_context;
1490 auto surface = std::make_unique<egl::MockWindowSurface>();
1491 auto surface_ptr = surface.get();
1493 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1494 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1495 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1496 .WillOnce(Return(
false));
1498 EXPECT_CALL(*egl_manager.get(), render_context)
1499 .WillOnce(Return(&render_context));
1500 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1503 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1504 .WillOnce(Return(std::move(surface)));
1505 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1506 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1507 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1509 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1511 EngineModifier modifier{engine.get()};
1512 modifier.SetEGLManager(std::move(egl_manager));
1514 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1515 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1520 TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) {
1521 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1522 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1523 auto egl_manager = std::make_unique<egl::MockManager>();
1524 egl::MockContext render_context;
1525 auto surface = std::make_unique<egl::MockWindowSurface>();
1526 auto surface_ptr = surface.get();
1528 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1529 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1530 .WillOnce(Return(
true));
1532 EXPECT_CALL(*egl_manager.get(), render_context)
1533 .WillOnce(Return(&render_context));
1534 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1537 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1538 .WillOnce(Return(std::move(surface)));
1539 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1540 .WillOnce([](fml::closure
callback) {
1544 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1545 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1546 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1547 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1548 .WillOnce([](fml::closure
callback) {
1552 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1554 EngineModifier modifier{engine.get()};
1555 modifier.SetEGLManager(std::move(egl_manager));
1557 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1558 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1563 TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) {
1564 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1565 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1566 auto egl_manager = std::make_unique<egl::MockManager>();
1567 egl::MockContext render_context;
1568 auto surface = std::make_unique<egl::MockWindowSurface>();
1569 auto surface_ptr = surface.get();
1571 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1573 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1574 .WillOnce(Return(
false));
1576 EXPECT_CALL(*egl_manager.get(), render_context)
1577 .WillOnce(Return(&render_context));
1578 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1581 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1582 .WillOnce(Return(std::move(surface)));
1583 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1584 .WillOnce([](fml::closure
callback) {
1589 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1590 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1591 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1593 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1594 .WillOnce([](fml::closure
callback) {
1598 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1600 EngineModifier modifier{engine.get()};
1601 modifier.SetEGLManager(std::move(egl_manager));
1603 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1604 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1610 TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) {
1611 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1612 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1613 auto egl_manager = std::make_unique<egl::MockManager>();
1614 egl::MockContext render_context;
1615 auto surface = std::make_unique<egl::MockWindowSurface>();
1616 auto surface_ptr = surface.get();
1618 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1620 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1621 .WillRepeatedly([](fml::closure
callback) {
1626 EXPECT_CALL(*egl_manager.get(), render_context)
1627 .WillRepeatedly(Return(&render_context));
1629 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
1630 EXPECT_CALL(*surface_ptr, MakeCurrent).WillRepeatedly(Return(
true));
1631 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1632 EXPECT_CALL(render_context, ClearCurrent).WillRepeatedly(Return(
true));
1637 std::unique_ptr<FlutterWindowsView> view;
1639 EXPECT_CALL(*egl_manager, CreateWindowSurface)
1640 .WillOnce(Return(std::move(surface)));
1641 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1642 .WillOnce(Return(
true));
1643 EXPECT_CALL(*surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
1645 EngineModifier engine_modifier{engine.get()};
1646 engine_modifier.SetEGLManager(std::move(egl_manager));
1648 view = engine->CreateView(
1649 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1654 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1655 .WillOnce(Return(
false));
1656 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1658 engine->OnDwmCompositionChanged();
1663 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1664 .WillOnce(Return(
true));
1665 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1667 engine->OnDwmCompositionChanged();
1671 TEST(FlutterWindowsViewTest, FocusTriggersWindowFocus) {
1672 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1673 auto window_binding_handler =
1674 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1675 EXPECT_CALL(*window_binding_handler, Focus()).WillOnce(Return(
true));
1676 std::unique_ptr<FlutterWindowsView> view =
1677 engine->CreateView(std::move(window_binding_handler));
1678 EXPECT_TRUE(view->Focus());
1681 TEST(FlutterWindowsViewTest, OnFocusTriggersSendFocusViewEvent) {
1682 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1683 auto window_binding_handler =
1684 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1685 std::unique_ptr<FlutterWindowsView> view =
1686 engine->CreateView(std::move(window_binding_handler));
1688 EngineModifier modifier(engine.get());
1689 bool received_focus_event =
false;
1690 modifier.embedder_api().SendViewFocusEvent = MOCK_ENGINE_PROC(
1691 SendViewFocusEvent, [&](FLUTTER_API_SYMBOL(
FlutterEngine) raw_engine,
1692 FlutterViewFocusEvent
const* event) {
1693 EXPECT_EQ(event->state, FlutterViewFocusState::kFocused);
1694 EXPECT_EQ(event->direction, FlutterViewFocusDirection::kUndefined);
1695 EXPECT_EQ(event->view_id, view->view_id());
1696 EXPECT_EQ(event->struct_size,
sizeof(FlutterViewFocusEvent));
1697 received_focus_event =
true;
1700 view->OnFocus(FlutterViewFocusState::kFocused,
1701 FlutterViewFocusDirection::kUndefined);
1702 EXPECT_TRUE(received_focus_event);