7 #include <UIAutomation.h>
15 #include "flutter/fml/synchronization/waitable_event.h"
17 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
21 #include "flutter/shell/platform/windows/testing/egl/mock_context.h"
22 #include "flutter/shell/platform/windows/testing/egl/mock_manager.h"
23 #include "flutter/shell/platform/windows/testing/egl/mock_window_surface.h"
24 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
25 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
26 #include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
27 #include "flutter/shell/platform/windows/testing/test_keyboard.h"
28 #include "flutter/shell/platform/windows/testing/view_modifier.h"
30 #include "gmock/gmock.h"
31 #include "gtest/gtest.h"
37 using ::testing::InSequence;
38 using ::testing::NiceMock;
39 using ::testing::Return;
50 struct TestResponseHandle {
55 static bool test_response =
false;
57 constexpr uint64_t kKeyEventFromChannel = 0x11;
58 constexpr uint64_t kKeyEventFromEmbedder = 0x22;
59 static std::vector<int> key_event_logs;
61 std::unique_ptr<std::vector<uint8_t>> keyHandlingResponse(
bool handled) {
62 rapidjson::Document document;
63 auto& allocator = document.GetAllocator();
65 document.AddMember(
"handled", test_response, allocator);
71 FlutterProjectBundle GetTestProject() {
73 properties.
assets_path = L
"C:\\foo\\flutter_assets";
77 return FlutterProjectBundle{properties};
83 std::unique_ptr<FlutterWindowsEngine> GetTestEngine(
84 std::shared_ptr<WindowsProcTable> windows_proc_table =
nullptr) {
85 auto engine = std::make_unique<FlutterWindowsEngine>(
86 GetTestProject(), std::move(windows_proc_table));
88 EngineModifier modifier(engine.get());
90 auto key_response_controller = std::make_shared<MockKeyResponseController>();
91 key_response_controller->SetChannelResponse(
92 [](MockKeyResponseController::ResponseCallback
callback) {
93 key_event_logs.push_back(kKeyEventFromChannel);
96 key_response_controller->SetEmbedderResponse(
97 [](
const FlutterKeyEvent* event,
98 MockKeyResponseController::ResponseCallback
callback) {
99 key_event_logs.push_back(kKeyEventFromEmbedder);
102 modifier.embedder_api().NotifyDisplayUpdate =
103 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
104 ([engine_instance = engine.get()](
105 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
106 const FlutterEngineDisplaysUpdateType update_type,
107 const FlutterEngineDisplay* embedder_displays,
108 size_t display_count) {
return kSuccess; }));
110 MockEmbedderApiForKeyboard(modifier, key_response_controller);
116 class MockFlutterWindowsEngine :
public FlutterWindowsEngine {
118 explicit MockFlutterWindowsEngine(
119 std::shared_ptr<WindowsProcTable> windows_proc_table =
nullptr)
120 : FlutterWindowsEngine(GetTestProject(), std::move(windows_proc_table)) {}
122 MOCK_METHOD(
bool, running, (), (
const));
123 MOCK_METHOD(
bool, Stop, (), ());
124 MOCK_METHOD(
bool, PostRasterThreadTask, (fml::closure), (
const));
127 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsEngine);
134 TEST(FlutterWindowsViewTest, SubMenuExpandedState) {
135 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
136 EngineModifier modifier(engine.get());
137 modifier.embedder_api().UpdateSemanticsEnabled =
142 auto window_binding_handler =
143 std::make_unique<NiceMock<MockWindowBindingHandler>>();
144 std::unique_ptr<FlutterWindowsView> view =
145 engine->CreateView(std::move(window_binding_handler));
148 view->OnUpdateSemanticsEnabled(
true);
150 auto bridge = view->accessibility_bridge().lock();
153 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
158 root.increased_value =
"";
159 root.decreased_value =
"";
160 root.child_count = 0;
161 root.custom_accessibility_actions_count = 0;
162 root.flags =
static_cast<FlutterSemanticsFlag
>(
163 FlutterSemanticsFlag::kFlutterSemanticsFlagHasExpandedState |
164 FlutterSemanticsFlag::kFlutterSemanticsFlagIsExpanded);
165 bridge->AddFlutterSemanticsNodeUpdate(root);
167 bridge->CommitUpdates();
170 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
171 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kExpanded));
174 IAccessible* native_view = root_node->GetNativeViewAccessible();
175 ASSERT_TRUE(native_view !=
nullptr);
178 VARIANT varchild = {};
182 varchild.lVal = CHILDID_SELF;
183 VARIANT native_state = {};
184 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
185 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_EXPANDED);
188 IRawElementProviderSimple* uia_node;
189 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
190 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
191 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
192 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Expanded);
194 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
195 UIA_AriaPropertiesPropertyId, &native_state)));
196 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=true"),
nullptr);
200 root.flags =
static_cast<FlutterSemanticsFlag
>(
201 FlutterSemanticsFlag::kFlutterSemanticsFlagHasExpandedState);
202 bridge->AddFlutterSemanticsNodeUpdate(root);
203 bridge->CommitUpdates();
206 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
207 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kCollapsed));
210 IAccessible* native_view = root_node->GetNativeViewAccessible();
211 ASSERT_TRUE(native_view !=
nullptr);
214 VARIANT varchild = {};
218 varchild.lVal = CHILDID_SELF;
219 VARIANT native_state = {};
220 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
221 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_COLLAPSED);
224 IRawElementProviderSimple* uia_node;
225 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
226 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
227 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
228 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Collapsed);
230 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
231 UIA_AriaPropertiesPropertyId, &native_state)));
232 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=false"),
nullptr);
238 TEST(FlutterWindowsViewTest, Shutdown) {
239 auto engine = std::make_unique<MockFlutterWindowsEngine>();
240 auto window_binding_handler =
241 std::make_unique<NiceMock<MockWindowBindingHandler>>();
242 auto egl_manager = std::make_unique<egl::MockManager>();
243 auto surface = std::make_unique<egl::MockWindowSurface>();
244 auto surface_ptr = surface.get();
246 EngineModifier modifier{engine.get()};
247 modifier.SetEGLManager(std::move(egl_manager));
250 std::unique_ptr<FlutterWindowsView> view =
251 engine->CreateView(std::move(window_binding_handler));
253 ViewModifier view_modifier{view.get()};
254 view_modifier.SetSurface(std::move(surface));
258 EXPECT_CALL(*engine.get(), Stop).Times(1);
259 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
263 TEST(FlutterWindowsViewTest, KeySequence) {
264 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
266 test_response =
false;
268 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
269 std::make_unique<NiceMock<MockWindowBindingHandler>>());
272 [](
bool handled) {});
274 EXPECT_EQ(key_event_logs.size(), 2);
275 EXPECT_EQ(key_event_logs[0], kKeyEventFromEmbedder);
276 EXPECT_EQ(key_event_logs[1], kKeyEventFromChannel);
278 key_event_logs.clear();
281 TEST(FlutterWindowsViewTest, EnableSemantics) {
282 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
283 EngineModifier modifier(engine.get());
285 bool semantics_enabled =
false;
286 modifier.embedder_api().UpdateSemanticsEnabled = MOCK_ENGINE_PROC(
287 UpdateSemanticsEnabled,
288 [&semantics_enabled](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
290 semantics_enabled = enabled;
294 auto window_binding_handler =
295 std::make_unique<NiceMock<MockWindowBindingHandler>>();
296 std::unique_ptr<FlutterWindowsView> view =
297 engine->CreateView(std::move(window_binding_handler));
299 view->OnUpdateSemanticsEnabled(
true);
300 EXPECT_TRUE(semantics_enabled);
303 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdate) {
304 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
305 EngineModifier modifier(engine.get());
306 modifier.embedder_api().UpdateSemanticsEnabled =
311 auto window_binding_handler =
312 std::make_unique<NiceMock<MockWindowBindingHandler>>();
313 std::unique_ptr<FlutterWindowsView> view =
314 engine->CreateView(std::move(window_binding_handler));
317 view->OnUpdateSemanticsEnabled(
true);
319 auto bridge = view->accessibility_bridge().lock();
323 FlutterSemanticsNode2 node{
sizeof(FlutterSemanticsNode2), 0};
325 node.value =
"value";
326 node.platform_view_id = -1;
327 bridge->AddFlutterSemanticsNodeUpdate(node);
328 bridge->CommitUpdates();
331 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
336 IAccessible* native_view =
node_delegate->GetNativeViewAccessible();
337 ASSERT_TRUE(native_view !=
nullptr);
342 varchild.lVal = CHILDID_SELF;
345 BSTR bname =
nullptr;
346 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
347 std::string name(_com_util::ConvertBSTRToString(bname));
348 EXPECT_EQ(name,
"name");
351 BSTR bvalue =
nullptr;
352 ASSERT_EQ(native_view->get_accValue(varchild, &bvalue), S_OK);
353 std::string value(_com_util::ConvertBSTRToString(bvalue));
354 EXPECT_EQ(value,
"value");
359 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
360 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
363 IRawElementProviderSimple* uia_view;
364 native_view->QueryInterface(IID_PPV_ARGS(&uia_view));
365 ASSERT_TRUE(uia_view !=
nullptr);
369 ASSERT_EQ(uia_view->GetPropertyValue(UIA_NamePropertyId, &varname), S_OK);
370 EXPECT_EQ(varname.vt, VT_BSTR);
371 name = _com_util::ConvertBSTRToString(varname.bstrVal);
372 EXPECT_EQ(name,
"name");
376 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue),
378 EXPECT_EQ(varvalue.vt, VT_BSTR);
379 value = _com_util::ConvertBSTRToString(varvalue.bstrVal);
380 EXPECT_EQ(value,
"value");
384 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
386 EXPECT_EQ(varrole.vt, VT_I4);
387 EXPECT_EQ(varrole.lVal, UIA_TextControlTypeId);
402 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdateWithChildren) {
403 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
404 EngineModifier modifier(engine.get());
405 modifier.embedder_api().UpdateSemanticsEnabled =
410 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
411 std::make_unique<NiceMock<MockWindowBindingHandler>>());
414 view->OnUpdateSemanticsEnabled(
true);
416 auto bridge = view->accessibility_bridge().lock();
420 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
421 std::vector<int32_t> node0_children{1, 2};
422 node0.child_count = node0_children.size();
423 node0.children_in_traversal_order = node0_children.data();
424 node0.children_in_hit_test_order = node0_children.data();
426 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
427 node1.label =
"prefecture";
428 node1.value =
"Kyoto";
429 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
430 std::vector<int32_t> node2_children{3};
431 node2.child_count = node2_children.size();
432 node2.children_in_traversal_order = node2_children.data();
433 node2.children_in_hit_test_order = node2_children.data();
434 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
435 node3.label =
"city";
438 bridge->AddFlutterSemanticsNodeUpdate(node0);
439 bridge->AddFlutterSemanticsNodeUpdate(node1);
440 bridge->AddFlutterSemanticsNodeUpdate(node2);
441 bridge->AddFlutterSemanticsNodeUpdate(node3);
442 bridge->CommitUpdates();
445 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
450 IAccessible* node0_accessible =
node_delegate->GetNativeViewAccessible();
451 ASSERT_TRUE(node0_accessible !=
nullptr);
456 varchild.lVal = CHILDID_SELF;
461 ASSERT_EQ(node0_accessible->get_accRole(varchild, &varrole), S_OK);
462 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
465 long node0_child_count = 0;
466 ASSERT_EQ(node0_accessible->get_accChildCount(&node0_child_count), S_OK);
467 EXPECT_EQ(node0_child_count, 2);
472 IDispatch* node1_dispatch =
nullptr;
473 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node1_dispatch), S_OK);
474 ASSERT_TRUE(node1_dispatch !=
nullptr);
475 IAccessible* node1_accessible =
nullptr;
476 ASSERT_EQ(node1_dispatch->QueryInterface(
477 IID_IAccessible,
reinterpret_cast<void**
>(&node1_accessible)),
479 ASSERT_TRUE(node1_accessible !=
nullptr);
482 varchild.lVal = CHILDID_SELF;
483 BSTR bname =
nullptr;
484 ASSERT_EQ(node1_accessible->get_accName(varchild, &bname), S_OK);
485 std::string name(_com_util::ConvertBSTRToString(bname));
486 EXPECT_EQ(name,
"prefecture");
489 BSTR bvalue =
nullptr;
490 ASSERT_EQ(node1_accessible->get_accValue(varchild, &bvalue), S_OK);
491 std::string value(_com_util::ConvertBSTRToString(bvalue));
492 EXPECT_EQ(value,
"Kyoto");
497 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
498 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
501 IDispatch* parent_dispatch;
502 node1_accessible->get_accParent(&parent_dispatch);
503 IAccessible* parent_accessible;
505 parent_dispatch->QueryInterface(
506 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
508 EXPECT_EQ(parent_accessible, node0_accessible);
513 IDispatch* node2_dispatch =
nullptr;
514 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
515 ASSERT_TRUE(node2_dispatch !=
nullptr);
516 IAccessible* node2_accessible =
nullptr;
517 ASSERT_EQ(node2_dispatch->QueryInterface(
518 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
520 ASSERT_TRUE(node2_accessible !=
nullptr);
524 long node2_child_count = 0;
525 ASSERT_EQ(node2_accessible->get_accChildCount(&node2_child_count), S_OK);
526 EXPECT_EQ(node2_child_count, 1);
529 varchild.lVal = CHILDID_SELF;
532 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
533 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
536 IDispatch* parent_dispatch;
537 node2_accessible->get_accParent(&parent_dispatch);
538 IAccessible* parent_accessible;
540 parent_dispatch->QueryInterface(
541 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
543 EXPECT_EQ(parent_accessible, node0_accessible);
549 IDispatch* node3_dispatch =
nullptr;
550 ASSERT_EQ(node2_accessible->get_accChild(varchild, &node3_dispatch), S_OK);
551 ASSERT_TRUE(node3_dispatch !=
nullptr);
552 IAccessible* node3_accessible =
nullptr;
553 ASSERT_EQ(node3_dispatch->QueryInterface(
554 IID_IAccessible,
reinterpret_cast<void**
>(&node3_accessible)),
556 ASSERT_TRUE(node3_accessible !=
nullptr);
559 varchild.lVal = CHILDID_SELF;
560 BSTR bname =
nullptr;
561 ASSERT_EQ(node3_accessible->get_accName(varchild, &bname), S_OK);
562 std::string name(_com_util::ConvertBSTRToString(bname));
563 EXPECT_EQ(name,
"city");
566 BSTR bvalue =
nullptr;
567 ASSERT_EQ(node3_accessible->get_accValue(varchild, &bvalue), S_OK);
568 std::string value(_com_util::ConvertBSTRToString(bvalue));
569 EXPECT_EQ(value,
"Uji");
574 ASSERT_EQ(node3_accessible->get_accRole(varchild, &varrole), S_OK);
575 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
578 IDispatch* parent_dispatch;
579 node3_accessible->get_accParent(&parent_dispatch);
580 IAccessible* parent_accessible;
582 parent_dispatch->QueryInterface(
583 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
585 EXPECT_EQ(parent_accessible, node2_accessible);
598 TEST(FlutterWindowsViewTest, NonZeroSemanticsRoot) {
599 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
600 EngineModifier modifier(engine.get());
601 modifier.embedder_api().UpdateSemanticsEnabled =
606 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
607 std::make_unique<NiceMock<MockWindowBindingHandler>>());
610 view->OnUpdateSemanticsEnabled(
true);
612 auto bridge = view->accessibility_bridge().lock();
616 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
617 std::vector<int32_t> node1_children{2};
618 node1.child_count = node1_children.size();
619 node1.children_in_traversal_order = node1_children.data();
620 node1.children_in_hit_test_order = node1_children.data();
622 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
623 node2.label =
"prefecture";
624 node2.value =
"Kyoto";
626 bridge->AddFlutterSemanticsNodeUpdate(node1);
627 bridge->AddFlutterSemanticsNodeUpdate(node2);
628 bridge->CommitUpdates();
631 auto root_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
632 ASSERT_TRUE(root_delegate);
633 EXPECT_EQ(root_delegate->GetChildCount(), 1);
636 auto child_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
637 ASSERT_TRUE(child_delegate);
638 EXPECT_EQ(child_delegate->GetChildCount(), 0);
641 auto fake_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
642 ASSERT_FALSE(fake_delegate);
645 IAccessible* node1_accessible = root_delegate->GetNativeViewAccessible();
646 ASSERT_TRUE(node1_accessible !=
nullptr);
651 varchild.lVal = CHILDID_SELF;
656 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
657 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
660 long node1_child_count = 0;
661 ASSERT_EQ(node1_accessible->get_accChildCount(&node1_child_count), S_OK);
662 EXPECT_EQ(node1_child_count, 1);
667 IDispatch* node2_dispatch =
nullptr;
668 ASSERT_EQ(node1_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
669 ASSERT_TRUE(node2_dispatch !=
nullptr);
670 IAccessible* node2_accessible =
nullptr;
671 ASSERT_EQ(node2_dispatch->QueryInterface(
672 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
674 ASSERT_TRUE(node2_accessible !=
nullptr);
677 varchild.lVal = CHILDID_SELF;
678 BSTR bname =
nullptr;
679 ASSERT_EQ(node2_accessible->get_accName(varchild, &bname), S_OK);
680 std::string name(_com_util::ConvertBSTRToString(bname));
681 EXPECT_EQ(name,
"prefecture");
684 BSTR bvalue =
nullptr;
685 ASSERT_EQ(node2_accessible->get_accValue(varchild, &bvalue), S_OK);
686 std::string value(_com_util::ConvertBSTRToString(bvalue));
687 EXPECT_EQ(value,
"Kyoto");
692 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
693 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
696 IDispatch* parent_dispatch;
697 node2_accessible->get_accParent(&parent_dispatch);
698 IAccessible* parent_accessible;
700 parent_dispatch->QueryInterface(
701 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
703 EXPECT_EQ(parent_accessible, node1_accessible);
724 TEST(FlutterWindowsViewTest, AccessibilityHitTesting) {
725 constexpr FlutterTransformation kIdentityTransform = {1, 0, 0,
729 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
730 EngineModifier modifier(engine.get());
731 modifier.embedder_api().UpdateSemanticsEnabled =
736 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
737 std::make_unique<NiceMock<MockWindowBindingHandler>>());
740 view->OnUpdateSemanticsEnabled(
true);
742 auto bridge = view->accessibility_bridge().lock();
746 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
747 std::vector<int32_t> node0_children{1, 2};
748 node0.rect = {0, 0, 500, 500};
749 node0.transform = kIdentityTransform;
750 node0.child_count = node0_children.size();
751 node0.children_in_traversal_order = node0_children.data();
752 node0.children_in_hit_test_order = node0_children.data();
755 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
756 node1.rect = {0, 0, 250, 500};
757 node1.transform = kIdentityTransform;
758 node1.label =
"prefecture";
759 node1.value =
"Kyoto";
762 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
763 std::vector<int32_t> node2_children{3};
764 node2.rect = {0, 0, 250, 500};
765 node2.transform = {1, 0, 250, 0, 1, 0, 0, 0, 1};
766 node2.child_count = node2_children.size();
767 node2.children_in_traversal_order = node2_children.data();
768 node2.children_in_hit_test_order = node2_children.data();
771 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
772 node3.rect = {0, 0, 250, 250};
773 node3.transform = {1, 0, 0, 0, 1, 250, 0, 0, 1};
774 node3.label =
"city";
777 bridge->AddFlutterSemanticsNodeUpdate(node0);
778 bridge->AddFlutterSemanticsNodeUpdate(node1);
779 bridge->AddFlutterSemanticsNodeUpdate(node2);
780 bridge->AddFlutterSemanticsNodeUpdate(node3);
781 bridge->CommitUpdates();
784 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
785 ASSERT_TRUE(node0_delegate);
786 auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
787 ASSERT_TRUE(node1_delegate);
788 auto node2_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
789 ASSERT_TRUE(node2_delegate);
790 auto node3_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(3).lock();
791 ASSERT_TRUE(node3_delegate);
794 IAccessible* node0_accessible = node0_delegate->GetNativeViewAccessible();
795 ASSERT_TRUE(node0_accessible !=
nullptr);
799 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(150, 150, &varchild)));
800 EXPECT_EQ(varchild.vt, VT_DISPATCH);
801 EXPECT_EQ(varchild.pdispVal, node1_delegate->GetNativeViewAccessible());
805 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 150, &varchild)));
806 EXPECT_EQ(varchild.vt, VT_DISPATCH);
807 EXPECT_EQ(varchild.pdispVal, node2_delegate->GetNativeViewAccessible());
811 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 450, &varchild)));
812 EXPECT_EQ(varchild.vt, VT_DISPATCH);
813 EXPECT_EQ(varchild.pdispVal, node3_delegate->GetNativeViewAccessible());
816 TEST(FlutterWindowsViewTest, WindowResizeTests) {
817 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
818 std::unique_ptr<FlutterWindowsEngine> engine =
819 GetTestEngine(windows_proc_table);
820 EngineModifier engine_modifier{engine.get()};
822 auto egl_manager = std::make_unique<egl::MockManager>();
823 auto surface = std::make_unique<egl::MockWindowSurface>();
824 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
825 auto resized_surface_ptr = resized_surface.get();
827 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
828 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
830 EXPECT_CALL(*egl_manager.get(),
831 CreateWindowSurface(_, 500, 500))
832 .WillOnce(Return(std::move((resized_surface))));
833 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
834 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
835 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
837 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
839 engine_modifier.SetEGLManager(std::move(egl_manager));
841 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
842 std::make_unique<NiceMock<MockWindowBindingHandler>>());
844 ViewModifier view_modifier{view.get()};
845 view_modifier.SetSurface(std::move(surface));
847 fml::AutoResetWaitableEvent metrics_sent_latch;
848 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
849 SendWindowMetricsEvent,
850 ([&metrics_sent_latch](
auto engine,
851 const FlutterWindowMetricsEvent* event) {
852 metrics_sent_latch.Signal();
856 fml::AutoResetWaitableEvent resized_latch;
857 std::thread([&resized_latch, &view]() {
860 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
861 resized_latch.Signal();
865 metrics_sent_latch.Wait();
868 ASSERT_TRUE(view->OnFrameGenerated(500, 500));
869 view->OnFramePresented();
870 resized_latch.Wait();
874 TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) {
875 auto windows_proc_table = std::make_shared<NiceMock<MockWindowsProcTable>>();
876 std::unique_ptr<FlutterWindowsEngine> engine =
877 GetTestEngine(windows_proc_table);
878 EngineModifier engine_modifier{engine.get()};
880 auto egl_manager = std::make_unique<egl::MockManager>();
881 auto surface = std::make_unique<egl::MockWindowSurface>();
882 auto resized_surface = std::make_unique<egl::MockWindowSurface>();
883 auto resized_surface_ptr = resized_surface.get();
885 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
886 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
888 EXPECT_CALL(*egl_manager.get(),
889 CreateWindowSurface(_, 500, 500))
890 .WillOnce(Return(std::move((resized_surface))));
891 EXPECT_CALL(*resized_surface_ptr, MakeCurrent).WillOnce(Return(
true));
892 EXPECT_CALL(*resized_surface_ptr, SetVSyncEnabled).WillOnce(Return(
true));
893 EXPECT_CALL(*windows_proc_table.get(), DwmFlush).WillOnce(Return(S_OK));
895 EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(
true));
897 fml::AutoResetWaitableEvent metrics_sent_latch;
898 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
899 SendWindowMetricsEvent,
900 ([&metrics_sent_latch](
auto engine,
901 const FlutterWindowMetricsEvent* event) {
902 metrics_sent_latch.Signal();
906 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
907 std::make_unique<NiceMock<MockWindowBindingHandler>>());
909 ViewModifier view_modifier{view.get()};
910 engine_modifier.SetEGLManager(std::move(egl_manager));
911 view_modifier.SetSurface(std::move(surface));
913 fml::AutoResetWaitableEvent resized_latch;
914 std::thread([&resized_latch, &view]() {
917 EXPECT_TRUE(view->OnWindowSizeChanged(500, 500));
918 resized_latch.Signal();
922 metrics_sent_latch.Wait();
925 view->OnEmptyFrameGenerated();
926 view->OnFramePresented();
927 resized_latch.Wait();
933 TEST(FlutterWindowsViewTest, WindowResizeRace) {
934 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
935 EngineModifier engine_modifier(engine.get());
937 auto egl_manager = std::make_unique<egl::MockManager>();
938 auto surface = std::make_unique<egl::MockWindowSurface>();
940 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
true));
941 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
true));
943 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
944 std::make_unique<NiceMock<MockWindowBindingHandler>>());
946 ViewModifier view_modifier{view.get()};
947 engine_modifier.SetEGLManager(std::move(egl_manager));
948 view_modifier.SetSurface(std::move(surface));
951 ASSERT_TRUE(view->OnFrameGenerated(100, 100));
955 fml::AutoResetWaitableEvent resized_latch;
956 std::thread([&resized_latch, &view]() {
958 EXPECT_FALSE(view->OnWindowSizeChanged(500, 500));
959 resized_latch.Signal();
963 resized_latch.Wait();
968 view->OnFramePresented();
973 TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) {
974 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
975 EngineModifier engine_modifier(engine.get());
977 auto egl_manager = std::make_unique<egl::MockManager>();
978 auto surface = std::make_unique<egl::MockWindowSurface>();
980 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
981 EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(
false));
982 EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(
false));
984 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
985 std::make_unique<NiceMock<MockWindowBindingHandler>>());
987 ViewModifier view_modifier{view.get()};
988 engine_modifier.SetEGLManager(std::move(egl_manager));
989 view_modifier.SetSurface(std::move(surface));
991 auto metrics_sent =
false;
992 engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
993 SendWindowMetricsEvent,
994 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
999 view->OnWindowSizeChanged(500, 500);
1004 TEST(FlutterWindowsViewTest, WindowResizeWithoutSurface) {
1005 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1006 EngineModifier modifier(engine.get());
1008 auto egl_manager = std::make_unique<egl::MockManager>();
1010 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0);
1012 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1013 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1015 modifier.SetEGLManager(std::move(egl_manager));
1017 auto metrics_sent =
false;
1018 modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1019 SendWindowMetricsEvent,
1020 ([&metrics_sent](
auto engine,
const FlutterWindowMetricsEvent* event) {
1021 metrics_sent =
true;
1025 view->OnWindowSizeChanged(500, 500);
1028 TEST(FlutterWindowsViewTest, WindowRepaintTests) {
1029 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1030 EngineModifier modifier(engine.get());
1033 std::make_unique<flutter::FlutterWindow>(100, 100)};
1035 bool schedule_frame_called =
false;
1036 modifier.embedder_api().ScheduleFrame =
1037 MOCK_ENGINE_PROC(ScheduleFrame, ([&schedule_frame_called](
auto engine) {
1038 schedule_frame_called =
true;
1042 view.OnWindowRepaint();
1043 EXPECT_TRUE(schedule_frame_called);
1052 TEST(FlutterWindowsViewTest, CheckboxNativeState) {
1053 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1054 EngineModifier modifier(engine.get());
1055 modifier.embedder_api().UpdateSemanticsEnabled =
1056 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1060 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1061 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1064 view->OnUpdateSemanticsEnabled(
true);
1066 auto bridge = view->accessibility_bridge().lock();
1067 ASSERT_TRUE(bridge);
1069 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1071 root.label =
"root";
1074 root.increased_value =
"";
1075 root.decreased_value =
"";
1076 root.child_count = 0;
1077 root.custom_accessibility_actions_count = 0;
1078 root.flags =
static_cast<FlutterSemanticsFlag
>(
1079 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
1080 FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked);
1081 bridge->AddFlutterSemanticsNodeUpdate(root);
1083 bridge->CommitUpdates();
1086 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1087 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1088 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1089 ax::mojom::CheckedState::kTrue);
1092 IAccessible* native_view = root_node->GetNativeViewAccessible();
1093 ASSERT_TRUE(native_view !=
nullptr);
1096 VARIANT varchild = {};
1097 varchild.vt = VT_I4;
1100 varchild.lVal = CHILDID_SELF;
1101 VARIANT native_state = {};
1102 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1103 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1106 IRawElementProviderSimple* uia_node;
1107 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1108 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1109 UIA_ToggleToggleStatePropertyId, &native_state)));
1110 EXPECT_EQ(native_state.lVal, ToggleState_On);
1112 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1113 UIA_AriaPropertiesPropertyId, &native_state)));
1114 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=true"),
nullptr);
1118 root.flags =
static_cast<FlutterSemanticsFlag
>(
1119 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState);
1120 bridge->AddFlutterSemanticsNodeUpdate(root);
1121 bridge->CommitUpdates();
1124 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1125 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1126 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1127 ax::mojom::CheckedState::kFalse);
1130 IAccessible* native_view = root_node->GetNativeViewAccessible();
1131 ASSERT_TRUE(native_view !=
nullptr);
1134 VARIANT varchild = {};
1135 varchild.vt = VT_I4;
1138 varchild.lVal = CHILDID_SELF;
1139 VARIANT native_state = {};
1140 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1141 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1144 IRawElementProviderSimple* uia_node;
1145 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1146 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1147 UIA_ToggleToggleStatePropertyId, &native_state)));
1148 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1150 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1151 UIA_AriaPropertiesPropertyId, &native_state)));
1152 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=false"),
nullptr);
1156 root.flags =
static_cast<FlutterSemanticsFlag
>(
1157 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
1158 FlutterSemanticsFlag::kFlutterSemanticsFlagIsCheckStateMixed);
1159 bridge->AddFlutterSemanticsNodeUpdate(root);
1160 bridge->CommitUpdates();
1163 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1164 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
1165 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1166 ax::mojom::CheckedState::kMixed);
1169 IAccessible* native_view = root_node->GetNativeViewAccessible();
1170 ASSERT_TRUE(native_view !=
nullptr);
1173 VARIANT varchild = {};
1174 varchild.vt = VT_I4;
1177 varchild.lVal = CHILDID_SELF;
1178 VARIANT native_state = {};
1179 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1180 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_MIXED);
1183 IRawElementProviderSimple* uia_node;
1184 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1185 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1186 UIA_ToggleToggleStatePropertyId, &native_state)));
1187 EXPECT_EQ(native_state.lVal, ToggleState_Indeterminate);
1189 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1190 UIA_AriaPropertiesPropertyId, &native_state)));
1191 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=mixed"),
nullptr);
1196 TEST(FlutterWindowsViewTest, SwitchNativeState) {
1197 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1198 EngineModifier modifier(engine.get());
1199 modifier.embedder_api().UpdateSemanticsEnabled =
1200 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1204 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1205 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1208 view->OnUpdateSemanticsEnabled(
true);
1210 auto bridge = view->accessibility_bridge().lock();
1211 ASSERT_TRUE(bridge);
1213 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1215 root.label =
"root";
1218 root.increased_value =
"";
1219 root.decreased_value =
"";
1220 root.child_count = 0;
1221 root.custom_accessibility_actions_count = 0;
1222 root.flags =
static_cast<FlutterSemanticsFlag
>(
1223 FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState |
1224 FlutterSemanticsFlag::kFlutterSemanticsFlagIsToggled);
1225 bridge->AddFlutterSemanticsNodeUpdate(root);
1227 bridge->CommitUpdates();
1230 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1231 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1232 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1233 ax::mojom::CheckedState::kTrue);
1236 IAccessible* native_view = root_node->GetNativeViewAccessible();
1237 ASSERT_TRUE(native_view !=
nullptr);
1240 VARIANT varchild = {};
1241 varchild.vt = VT_I4;
1243 varchild.lVal = CHILDID_SELF;
1244 VARIANT varrole = {};
1247 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
1248 ASSERT_EQ(varrole.lVal, ROLE_SYSTEM_CHECKBUTTON);
1251 VARIANT native_state = {};
1252 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1253 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_PRESSED);
1254 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1257 IRawElementProviderSimple* uia_node;
1258 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1259 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
1261 EXPECT_EQ(varrole.lVal, UIA_ButtonControlTypeId);
1262 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1265 EXPECT_EQ(native_state.lVal, ToggleState_On);
1267 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1269 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=true"),
nullptr);
1273 root.flags =
static_cast<FlutterSemanticsFlag
>(
1274 FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState);
1275 bridge->AddFlutterSemanticsNodeUpdate(root);
1276 bridge->CommitUpdates();
1279 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1280 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1281 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1282 ax::mojom::CheckedState::kFalse);
1285 IAccessible* native_view = root_node->GetNativeViewAccessible();
1286 ASSERT_TRUE(native_view !=
nullptr);
1289 VARIANT varchild = {};
1290 varchild.vt = VT_I4;
1293 varchild.lVal = CHILDID_SELF;
1294 VARIANT native_state = {};
1295 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1296 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_PRESSED);
1297 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1300 IRawElementProviderSimple* uia_node;
1301 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1302 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1305 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1307 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1309 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=false"),
nullptr);
1313 TEST(FlutterWindowsViewTest, TooltipNodeData) {
1314 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1315 EngineModifier modifier(engine.get());
1316 modifier.embedder_api().UpdateSemanticsEnabled =
1317 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1321 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1322 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1325 view->OnUpdateSemanticsEnabled(
true);
1327 auto bridge = view->accessibility_bridge().lock();
1328 ASSERT_TRUE(bridge);
1330 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1332 root.label =
"root";
1335 root.increased_value =
"";
1336 root.decreased_value =
"";
1337 root.tooltip =
"tooltip";
1338 root.child_count = 0;
1339 root.custom_accessibility_actions_count = 0;
1340 root.flags =
static_cast<FlutterSemanticsFlag
>(
1341 FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField);
1342 bridge->AddFlutterSemanticsNodeUpdate(root);
1344 bridge->CommitUpdates();
1345 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1346 std::string tooltip = root_node->GetData().GetStringAttribute(
1347 ax::mojom::StringAttribute::kTooltip);
1348 EXPECT_EQ(tooltip,
"tooltip");
1351 IAccessible* native_view = bridge->GetFlutterPlatformNodeDelegateFromID(0)
1353 ->GetNativeViewAccessible();
1354 VARIANT varchild = {.vt = VT_I4, .lVal = CHILDID_SELF};
1356 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
1357 EXPECT_NE(std::wcsstr(bname, L
"tooltip"),
nullptr);
1360 IRawElementProviderSimple* uia_node;
1361 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1363 ASSERT_EQ(uia_node->GetPropertyValue(UIA_HelpTextPropertyId, &varname), S_OK);
1364 std::string uia_tooltip = _com_util::ConvertBSTRToString(varname.bstrVal);
1365 EXPECT_EQ(uia_tooltip,
"tooltip");
1370 TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) {
1371 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1372 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1373 auto egl_manager = std::make_unique<egl::MockManager>();
1374 egl::MockContext render_context;
1375 auto surface = std::make_unique<egl::MockWindowSurface>();
1376 auto surface_ptr = surface.get();
1378 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1379 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1381 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1382 .WillOnce(Return(
true));
1384 EXPECT_CALL(*egl_manager.get(), render_context)
1385 .WillOnce(Return(&render_context));
1386 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1389 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1390 .WillOnce(Return(std::move(surface)));
1391 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1392 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1393 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1395 EXPECT_CALL(*engine.get(), Stop).Times(1);
1396 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1398 EngineModifier modifier{engine.get()};
1399 modifier.SetEGLManager(std::move(egl_manager));
1401 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1402 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1404 view->CreateRenderSurface();
1409 TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) {
1410 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1411 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1412 auto egl_manager = std::make_unique<egl::MockManager>();
1413 egl::MockContext render_context;
1414 auto surface = std::make_unique<egl::MockWindowSurface>();
1415 auto surface_ptr = surface.get();
1417 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1418 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1419 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1420 .WillOnce(Return(
false));
1422 EXPECT_CALL(*egl_manager.get(), render_context)
1423 .WillOnce(Return(&render_context));
1424 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1427 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1428 .WillOnce(Return(std::move(surface)));
1429 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1430 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1431 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1433 EXPECT_CALL(*engine.get(), Stop).Times(1);
1434 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1436 EngineModifier modifier{engine.get()};
1437 modifier.SetEGLManager(std::move(egl_manager));
1439 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1440 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1442 view->CreateRenderSurface();
1447 TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) {
1448 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1449 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1450 auto egl_manager = std::make_unique<egl::MockManager>();
1451 egl::MockContext render_context;
1452 auto surface = std::make_unique<egl::MockWindowSurface>();
1453 auto surface_ptr = surface.get();
1455 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1456 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1457 .WillOnce(Return(
true));
1459 EXPECT_CALL(*egl_manager.get(), render_context)
1460 .WillOnce(Return(&render_context));
1461 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1464 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1465 .WillOnce(Return(std::move(surface)));
1466 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1467 .WillOnce([](fml::closure
callback) {
1471 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1472 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1473 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1474 EXPECT_CALL(*engine.get(), Stop).Times(1);
1475 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1477 EngineModifier modifier{engine.get()};
1478 modifier.SetEGLManager(std::move(egl_manager));
1480 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1481 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1483 view->CreateRenderSurface();
1488 TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) {
1489 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1490 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1491 auto egl_manager = std::make_unique<egl::MockManager>();
1492 egl::MockContext render_context;
1493 auto surface = std::make_unique<egl::MockWindowSurface>();
1494 auto surface_ptr = surface.get();
1496 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1498 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1499 .WillOnce(Return(
false));
1501 EXPECT_CALL(*egl_manager.get(), render_context)
1502 .WillOnce(Return(&render_context));
1503 EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(
true));
1506 EXPECT_CALL(*egl_manager.get(), CreateWindowSurface)
1507 .WillOnce(Return(std::move(surface)));
1508 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1509 .WillOnce([](fml::closure
callback) {
1514 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1515 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1516 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1517 EXPECT_CALL(*engine.get(), Stop).Times(1);
1518 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1520 EngineModifier modifier{engine.get()};
1521 modifier.SetEGLManager(std::move(egl_manager));
1523 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1524 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1526 view->CreateRenderSurface();
1532 TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) {
1533 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1534 auto engine = std::make_unique<MockFlutterWindowsEngine>(windows_proc_table);
1535 auto egl_manager = std::make_unique<egl::MockManager>();
1536 egl::MockContext render_context;
1537 auto surface = std::make_unique<egl::MockWindowSurface>();
1538 auto surface_ptr = surface.get();
1540 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1542 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1543 .WillRepeatedly([](fml::closure
callback) {
1548 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1549 .WillOnce(Return(
false))
1550 .WillOnce(Return(
true));
1552 EXPECT_CALL(*egl_manager.get(), render_context)
1553 .WillRepeatedly(Return(&render_context));
1555 EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(
true));
1558 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1559 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
true)).WillOnce(Return(
true));
1560 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1562 EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(
true));
1563 EXPECT_CALL(*surface_ptr, SetVSyncEnabled(
false)).WillOnce(Return(
true));
1564 EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(
true));
1566 EXPECT_CALL(*engine.get(), Stop).Times(1);
1567 EXPECT_CALL(*surface_ptr, Destroy).Times(1);
1569 EngineModifier engine_modifier{engine.get()};
1570 engine_modifier.SetEGLManager(std::move(egl_manager));
1572 std::unique_ptr<FlutterWindowsView> view = engine->CreateView(
1573 std::make_unique<NiceMock<MockWindowBindingHandler>>());
1574 ViewModifier view_modifier{view.get()};
1575 view_modifier.SetSurface(std::move(surface));
1577 engine->OnDwmCompositionChanged();
1578 engine->OnDwmCompositionChanged();