| Flutter Windows Embedder |

flutter_window_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #include "flutter/fml/macros.h"
5 #include "flutter/shell/platform/windows/flutter_window.h"
6 #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
7 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler_delegate.h"
8 #include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
9 #include "flutter/shell/platform/windows/testing/windows_test.h"
10 #include "flutter/shell/platform/windows/testing/wm_builders.h"
11
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14
15 namespace flutter {
16 namespace testing {
17
18 using ::testing::_;
19 using ::testing::AnyNumber;
20 using ::testing::Eq;
21 using ::testing::Invoke;
22 using ::testing::Return;
23
24 namespace {
25 static constexpr int32_t kDefaultPointerDeviceId = 0;
26
27 class MockFlutterWindow : public FlutterWindow {
28 public:
29 explicit MockFlutterWindow(bool reset_view_on_exit = true)
30 : reset_view_on_exit_(reset_view_on_exit) {
31 ON_CALL(*this, GetDpiScale())
32 .WillByDefault(Return(this->FlutterWindow::GetDpiScale()));
33 }
34
35 // Used for injecting a proc_table to override calls to the windows API
36 MockFlutterWindow(int width,
37 int height,
38 std::shared_ptr<WindowsProcTable> proc_table = nullptr)
39 : FlutterWindow(width, height, nullptr, std::move(proc_table)) {}
40
41 virtual ~MockFlutterWindow() {
42 if (reset_view_on_exit_) {
43 SetView(nullptr);
44 }
45 }
46
47 // Wrapper for GetCurrentDPI() which is a protected method.
48 UINT GetDpi() { return GetCurrentDPI(); }
49 // Simulates a WindowProc message from the OS.
50 LRESULT InjectWindowMessage(UINT const message,
51 WPARAM const wparam,
52 LPARAM const lparam) {
53 return HandleMessage(message, wparam, lparam);
54 }
55
56 MOCK_METHOD(void, OnDpiScale, (unsigned int), (override));
57 MOCK_METHOD(void, OnResize, (unsigned int, unsigned int), (override));
58 MOCK_METHOD(float, GetScrollOffsetMultiplier, (), (override));
59 MOCK_METHOD(float, GetDpiScale, (), (override));
60 MOCK_METHOD(void, UpdateCursorRect, (const Rect&), (override));
61 MOCK_METHOD(void, OnResetImeComposing, (), (override));
62 MOCK_METHOD(UINT, Win32DispatchMessage, (UINT, WPARAM, LPARAM), (override));
63 MOCK_METHOD(BOOL, Win32PeekMessage, (LPMSG, UINT, UINT, UINT), (override));
64 MOCK_METHOD(uint32_t, Win32MapVkToChar, (uint32_t), (override));
65 MOCK_METHOD(HWND, GetWindowHandle, (), (override));
66 MOCK_METHOD(ui::AXFragmentRootDelegateWin*,
67 GetAxFragmentRootDelegate,
68 (),
69 (override));
70 MOCK_METHOD(void, OnWindowStateEvent, (WindowStateEvent), (override));
71
72 protected:
73 // |KeyboardManager::WindowDelegate|
74 LRESULT Win32DefWindowProc(HWND hWnd,
75 UINT Msg,
76 WPARAM wParam,
77 LPARAM lParam) override {
78 return kWmResultDefault;
79 }
80
81 private:
82 bool reset_view_on_exit_;
83 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindow);
84 };
85
86 class MockFlutterWindowsView : public FlutterWindowsView {
87 public:
88 MockFlutterWindowsView(FlutterWindowsEngine* engine,
89 std::unique_ptr<WindowBindingHandler> window_binding)
90 : FlutterWindowsView(kImplicitViewId,
91 engine,
92 std::move(window_binding),
93 false,
94 BoxConstraints()) {}
95 ~MockFlutterWindowsView() {}
96
97 MOCK_METHOD(void,
98 NotifyWinEventWrapper,
99 (ui::AXPlatformNodeWin*, ax::mojom::Event),
100 (override));
101
102 private:
103 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsView);
104 };
105
106 class FlutterWindowTest : public WindowsTest {};
107
108 } // namespace
109
110 TEST_F(FlutterWindowTest, CreateDestroy) {
111 std::unique_ptr<FlutterWindowsEngine> engine =
112 FlutterWindowsEngineBuilder{GetContext()}.Build();
113 FlutterWindow window(800, 600, engine->display_manager());
114 ASSERT_TRUE(TRUE);
115 }
116
117 TEST_F(FlutterWindowTest, OnBitmapSurfaceUpdated) {
118 std::unique_ptr<FlutterWindowsEngine> engine =
119 FlutterWindowsEngineBuilder{GetContext()}.Build();
120 FlutterWindow win32window(100, 100, engine->display_manager());
121 int old_handle_count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
122
123 constexpr size_t row_bytes = 100 * 4;
124 constexpr size_t height = 100;
125 std::array<char, row_bytes * height> allocation;
126 win32window.OnBitmapSurfaceUpdated(allocation.data(), row_bytes, height);
127
128 int new_handle_count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
129 // Check GDI resources leak
130 EXPECT_EQ(old_handle_count, new_handle_count);
131 }
132
133 // Tests that composing rect updates are transformed from Flutter logical
134 // coordinates to device coordinates and passed to the text input manager
135 // when the DPI scale is 100% (96 DPI).
136 TEST_F(FlutterWindowTest, OnCursorRectUpdatedRegularDPI) {
137 MockFlutterWindow win32window;
138 EXPECT_CALL(win32window, GetDpiScale()).WillOnce(Return(1.0));
139
140 Rect cursor_rect(Point(10, 20), Size(30, 40));
141 EXPECT_CALL(win32window, UpdateCursorRect(cursor_rect)).Times(1);
142
143 win32window.OnCursorRectUpdated(cursor_rect);
144 }
145
146 // Tests that composing rect updates are transformed from Flutter logical
147 // coordinates to device coordinates and passed to the text input manager
148 // when the DPI scale is 150% (144 DPI).
149 TEST_F(FlutterWindowTest, OnCursorRectUpdatedHighDPI) {
150 MockFlutterWindow win32window;
151 EXPECT_CALL(win32window, GetDpiScale()).WillOnce(Return(1.5));
152
153 Rect expected_cursor_rect(Point(15, 30), Size(45, 60));
154 EXPECT_CALL(win32window, UpdateCursorRect(expected_cursor_rect)).Times(1);
155
156 Rect cursor_rect(Point(10, 20), Size(30, 40));
157 win32window.OnCursorRectUpdated(cursor_rect);
158 }
159
160 TEST_F(FlutterWindowTest, OnPointerStarSendsDeviceType) {
161 std::unique_ptr<FlutterWindowsEngine> engine =
162 FlutterWindowsEngineBuilder{GetContext()}.Build();
163 FlutterWindow win32window(100, 100, engine->display_manager());
164 MockWindowBindingHandlerDelegate delegate;
165 EXPECT_CALL(delegate, OnWindowStateEvent).Times(AnyNumber());
166 win32window.SetView(&delegate);
167
168 // Move
169 EXPECT_CALL(delegate,
170 OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindMouse,
171 kDefaultPointerDeviceId, 0, 0, 0))
172 .Times(1);
173 EXPECT_CALL(delegate,
174 OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindTouch,
175 kDefaultPointerDeviceId, 0, 0, 0))
176 .Times(1);
177 EXPECT_CALL(delegate,
178 OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
179 kDefaultPointerDeviceId, 0, 0, 0))
180 .Times(1);
181
182 // Down
183 EXPECT_CALL(delegate,
184 OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindMouse,
185 kDefaultPointerDeviceId,
186 kFlutterPointerButtonMousePrimary, 0, 0))
187 .Times(1);
188 EXPECT_CALL(delegate,
189 OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindTouch,
190 kDefaultPointerDeviceId,
191 kFlutterPointerButtonMousePrimary, 0, 0))
192 .Times(1);
193 EXPECT_CALL(delegate,
194 OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
195 kDefaultPointerDeviceId,
196 kFlutterPointerButtonMousePrimary, 0, 0))
197 .Times(1);
198
199 // Up
200 EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindMouse,
201 kDefaultPointerDeviceId,
202 kFlutterPointerButtonMousePrimary))
203 .Times(1);
204 EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindTouch,
205 kDefaultPointerDeviceId,
206 kFlutterPointerButtonMousePrimary))
207 .Times(1);
208 EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindStylus,
209 kDefaultPointerDeviceId,
210 kFlutterPointerButtonMousePrimary))
211 .Times(1);
212
213 // Leave
214 EXPECT_CALL(delegate,
215 OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindMouse,
216 kDefaultPointerDeviceId))
217 .Times(1);
218 EXPECT_CALL(delegate,
219 OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindTouch,
220 kDefaultPointerDeviceId))
221 .Times(1);
222 EXPECT_CALL(delegate,
223 OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindStylus,
224 kDefaultPointerDeviceId))
225 .Times(1);
226
227 win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindMouse,
228 kDefaultPointerDeviceId, 0, 0, 0);
229 win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindMouse,
230 kDefaultPointerDeviceId, WM_LBUTTONDOWN, 0, 0);
231 win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindMouse,
232 kDefaultPointerDeviceId, WM_LBUTTONDOWN);
233 win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindMouse,
234 kDefaultPointerDeviceId);
235
236 // Touch
237 win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindTouch,
238 kDefaultPointerDeviceId, 0, 0, 0);
239 win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindTouch,
240 kDefaultPointerDeviceId, WM_LBUTTONDOWN, 0, 0);
241 win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindTouch,
242 kDefaultPointerDeviceId, WM_LBUTTONDOWN);
243 win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindTouch,
244 kDefaultPointerDeviceId);
245
246 // Pen
247 win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
248 kDefaultPointerDeviceId, 0, 0, 0);
249 win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
250 kDefaultPointerDeviceId, WM_LBUTTONDOWN, 0, 0);
251 win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindStylus,
252 kDefaultPointerDeviceId, WM_LBUTTONDOWN);
253 win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindStylus,
254 kDefaultPointerDeviceId);
255
256 // Destruction of win32window sends a HIDE update. In situ, the window is
257 // owned by the delegate, and so is destructed first. Not so here.
258 win32window.SetView(nullptr);
259 }
260
261 TEST_F(FlutterWindowTest, OnStylusPointerDown) {
262 auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
263
264 // Set up expectations for the mock
265 EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
266 .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
267 if (pointer_info != nullptr) {
268 pointer_info->pointerType = PT_PEN;
269 pointer_info->pointerId = pointer_id;
270 pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
271 }
272 return TRUE;
273 });
274
275 EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
276 .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
277 if (pen_info != nullptr) {
278 pen_info->pressure = 720; // Non-zero pressure for contact events
279 pen_info->rotation = 0;
280 }
281 return TRUE;
282 });
283
284 POINTER_INFO test_pointer_info = {};
285 BOOL result = mock_proc_table->GetPointerInfo(1, &test_pointer_info);
286
287 MockFlutterWindow win32window(100, 100, mock_proc_table);
288 MockWindowBindingHandlerDelegate delegate;
289
290 win32window.SetView(&delegate);
291
292 EXPECT_CALL(delegate,
293 OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
294 kDefaultPointerDeviceId,
295 kFlutterPointerButtonMousePrimary, 720, 0))
296 .Times(1);
297
298 UINT32 pointerId = 1;
299 WPARAM wparam = static_cast<WPARAM>(pointerId);
300 LPARAM lparam = MAKELPARAM(10, 10);
301
302 win32window.InjectWindowMessage(WM_POINTERDOWN, wparam, lparam);
303 }
304
305 TEST_F(FlutterWindowTest, OnStylusPointerMove) {
306 auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
307
308 EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
309 .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
310 if (pointer_info != nullptr) {
311 pointer_info->pointerType = PT_PEN;
312 pointer_info->pointerId = pointer_id;
313 pointer_info->pointerFlags =
314 POINTER_FLAG_INCONTACT | POINTER_FLAG_UPDATE;
315 }
316 return TRUE;
317 });
318
319 EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
320 .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
321 if (pen_info != nullptr) {
322 pen_info->pressure = 720; // Non-zero pressure for contact events
323 pen_info->rotation = 10; // This is PRE-transformation to radians.
324 }
325 return TRUE;
326 });
327
328 MockFlutterWindow win32window(100, 100, mock_proc_table);
329 MockWindowBindingHandlerDelegate delegate;
330 win32window.SetView(&delegate);
331
332 EXPECT_CALL(delegate, OnPointerMove(15, 20, kFlutterPointerDeviceKindStylus,
333 kDefaultPointerDeviceId, 10, 720, 0))
334 .Times(1);
335
336 UINT32 pointerId = 1;
337 WPARAM wparam = static_cast<WPARAM>(pointerId);
338 LPARAM lparam = MAKELPARAM(15, 20);
339
340 win32window.InjectWindowMessage(WM_POINTERUPDATE, wparam, lparam);
341 }
342
343 TEST_F(FlutterWindowTest, OnStylusPointerUp) {
344 auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
345
346 EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
347 .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
348 if (pointer_info != nullptr) {
349 pointer_info->pointerType = PT_PEN;
350 pointer_info->pointerId = pointer_id;
351 pointer_info->pointerFlags = POINTER_FLAG_UP;
352 }
353 return TRUE;
354 });
355
356 EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
357 .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
358 if (pen_info != nullptr) {
359 pen_info->pressure = 720;
360 pen_info->rotation = 0;
361 }
362 return TRUE;
363 });
364
365 MockFlutterWindow win32window(100, 100, mock_proc_table);
366 MockWindowBindingHandlerDelegate delegate;
367 win32window.SetView(&delegate);
368
369 EXPECT_CALL(delegate, OnPointerUp(25, 30, kFlutterPointerDeviceKindStylus,
370 kDefaultPointerDeviceId,
371 kFlutterPointerButtonMousePrimary))
372 .Times(1);
373
374 UINT32 pointerId = 1;
375 WPARAM wparam = static_cast<WPARAM>(pointerId);
376 LPARAM lparam = MAKELPARAM(25, 30);
377
378 win32window.InjectWindowMessage(WM_POINTERUP, wparam, lparam);
379 }
380
381 TEST_F(FlutterWindowTest, OnStylusPointerLeave) {
382 auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
383
384 EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
385 .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
386 if (pointer_info != nullptr) {
387 pointer_info->pointerType = PT_PEN;
388 pointer_info->pointerId = pointer_id;
389 pointer_info->pointerFlags = POINTER_FLAG_UP;
390 }
391 return TRUE;
392 });
393
394 EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
395 .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
396 if (pen_info != nullptr) {
397 pen_info->pressure = 720;
398 pen_info->rotation = 0;
399 }
400 return TRUE;
401 });
402
403 MockFlutterWindow win32window(100, 100, mock_proc_table);
404 MockWindowBindingHandlerDelegate delegate;
405 win32window.SetView(&delegate);
406
407 EXPECT_CALL(delegate, OnPointerLeave(35, 40, kFlutterPointerDeviceKindStylus,
408 kDefaultPointerDeviceId))
409 .Times(1);
410
411 UINT32 pointerId = 1;
412 WPARAM wparam = static_cast<WPARAM>(pointerId);
413 LPARAM lparam = MAKELPARAM(35, 40);
414
415 win32window.InjectWindowMessage(WM_POINTERLEAVE, wparam, lparam);
416 }
417
418 TEST_F(FlutterWindowTest, OnStylusPointerHover) {
419 // Test that WM_POINTERUPDATE without POINTER_FLAG_INCONTACT (hover) is
420 // handled
421 auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
422
423 EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
424 .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
425 if (pointer_info != nullptr) {
426 pointer_info->pointerId = 1;
427 pointer_info->pointerType = PT_PEN;
428 // No POINTER_FLAG_INCONTACT - this simulates a hover event
429 pointer_info->pointerFlags = POINTER_FLAG_UPDATE;
430 pointer_info->ptPixelLocation.x = 45;
431 pointer_info->ptPixelLocation.y = 50;
432 }
433 return TRUE;
434 });
435
436 EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
437 .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
438 if (pen_info != nullptr) {
439 pen_info->pressure = 0;
440 pen_info->rotation = 0;
441 }
442 return TRUE;
443 });
444
445 MockFlutterWindow win32window(100, 100, mock_proc_table);
446 MockWindowBindingHandlerDelegate delegate;
447 win32window.SetView(&delegate);
448
449 // First establish the pointer with WM_POINTERDOWN
450 EXPECT_CALL(delegate,
451 OnPointerDown(45, 50, kFlutterPointerDeviceKindStylus, 0,
452 kFlutterPointerButtonMousePrimary, 0, 0))
453 .Times(1);
454
455 UINT32 pointerId = 1;
456 WPARAM wparam = static_cast<WPARAM>(pointerId);
457 LPARAM lparam = MAKELPARAM(45, 50);
458 win32window.InjectWindowMessage(WM_POINTERDOWN, wparam, lparam);
459
460 // Now expect OnPointerMove to be called for hover events
461 EXPECT_CALL(delegate, OnPointerMove(45, 50, kFlutterPointerDeviceKindStylus,
462 0, 0, 0, 0))
463 .Times(1);
464
465 // Inject WM_POINTERUPDATE message (hover event)
466 win32window.InjectWindowMessage(WM_POINTERUPDATE, wparam, lparam);
467 }
468
469 TEST_F(FlutterWindowTest, OnMousePointerDown) {
470 auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
471
472 EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
473 .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
474 if (pointer_info != nullptr) {
475 pointer_info->pointerType = PT_MOUSE;
476 pointer_info->pointerId = pointer_id;
477 pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
478 }
479 return TRUE;
480 });
481
482 MockFlutterWindow win32window(100, 100, mock_proc_table);
483 MockWindowBindingHandlerDelegate delegate;
484 win32window.SetView(&delegate);
485
486 EXPECT_CALL(delegate, OnPointerDown(45, 50, kFlutterPointerDeviceKindMouse,
487 kDefaultPointerDeviceId,
488 kFlutterPointerButtonMousePrimary, 0, 0))
489 .Times(1);
490
491 UINT32 pointerId = 1;
492 WPARAM wparam = static_cast<WPARAM>(pointerId);
493 LPARAM lparam = MAKELPARAM(45, 50);
494
495 win32window.InjectWindowMessage(WM_POINTERDOWN, wparam, lparam);
496 }
497
498 TEST_F(FlutterWindowTest, OnTouchPointerDown) {
499 auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
500
501 EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
502 .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
503 if (pointer_info != nullptr) {
504 pointer_info->pointerType = PT_TOUCH;
505 pointer_info->pointerId = pointer_id;
506 pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
507 }
508 return TRUE;
509 });
510
511 MockFlutterWindow win32window(100, 100, mock_proc_table);
512 MockWindowBindingHandlerDelegate delegate;
513 win32window.SetView(&delegate);
514
515 EXPECT_CALL(delegate, OnPointerDown(55, 60, kFlutterPointerDeviceKindTouch,
516 kDefaultPointerDeviceId,
517 kFlutterPointerButtonMousePrimary, 0, 0))
518 .Times(1);
519
520 UINT32 pointerId = 1;
521 WPARAM wparam = static_cast<WPARAM>(pointerId);
522 LPARAM lparam = MAKELPARAM(55, 60);
523
524 win32window.InjectWindowMessage(WM_POINTERDOWN, wparam, lparam);
525 }
526
527 // Tests that calls to OnScroll in turn calls GetScrollOffsetMultiplier
528 // for mapping scroll ticks to pixels.
529 TEST_F(FlutterWindowTest, OnScrollCallsGetScrollOffsetMultiplier) {
530 MockFlutterWindow win32window;
531 MockWindowBindingHandlerDelegate delegate;
532 EXPECT_CALL(win32window, OnWindowStateEvent).Times(AnyNumber());
533 win32window.SetView(&delegate);
534
535 EXPECT_CALL(win32window, GetWindowHandle).WillOnce([&win32window]() {
536 return win32window.FlutterWindow::GetWindowHandle();
537 });
538 EXPECT_CALL(win32window, GetScrollOffsetMultiplier).WillOnce(Return(120.0f));
539
540 EXPECT_CALL(delegate,
541 OnScroll(_, _, 0, 0, 120.0f, kFlutterPointerDeviceKindMouse,
542 kDefaultPointerDeviceId))
543 .Times(1);
544
545 win32window.OnScroll(0.0f, 0.0f, kFlutterPointerDeviceKindMouse,
546 kDefaultPointerDeviceId);
547 }
548
549 TEST_F(FlutterWindowTest, OnWindowRepaint) {
550 MockFlutterWindow win32window;
551 MockWindowBindingHandlerDelegate delegate;
552 EXPECT_CALL(win32window, OnWindowStateEvent).Times(AnyNumber());
553 win32window.SetView(&delegate);
554
555 EXPECT_CALL(delegate, OnWindowRepaint()).Times(1);
556
557 win32window.InjectWindowMessage(WM_PAINT, 0, 0);
558 }
559
560 TEST_F(FlutterWindowTest, OnThemeChange) {
561 MockFlutterWindow win32window;
562 MockWindowBindingHandlerDelegate delegate;
563 EXPECT_CALL(win32window, OnWindowStateEvent).Times(AnyNumber());
564 win32window.SetView(&delegate);
565
566 EXPECT_CALL(delegate, OnHighContrastChanged).Times(1);
567
568 win32window.InjectWindowMessage(WM_THEMECHANGED, 0, 0);
569 }
570
571 // The window should return no root accessibility node if
572 // it isn't attached to a view.
573 // Regression test for https://github.com/flutter/flutter/issues/129791
574 TEST_F(FlutterWindowTest, AccessibilityNodeWithoutView) {
575 MockFlutterWindow win32window;
576
577 EXPECT_EQ(win32window.GetNativeViewAccessible(), nullptr);
578 }
579
580 // Ensure that announcing the alert propagates the message to the alert node.
581 // Different screen readers use different properties for alerts.
582 TEST_F(FlutterWindowTest, AlertNode) {
583 std::unique_ptr<FlutterWindowsEngine> engine =
584 FlutterWindowsEngineBuilder{GetContext()}.Build();
585 auto win32window = std::make_unique<MockFlutterWindow>();
586 EXPECT_CALL(*win32window.get(), GetAxFragmentRootDelegate())
587 .WillRepeatedly(Return(nullptr));
588 EXPECT_CALL(*win32window.get(), OnWindowStateEvent).Times(AnyNumber());
589 EXPECT_CALL(*win32window.get(), GetWindowHandle).Times(AnyNumber());
590 MockFlutterWindowsView view{engine.get(), std::move(win32window)};
591 std::wstring message = L"Test alert";
592 EXPECT_CALL(view, NotifyWinEventWrapper(_, ax::mojom::Event::kAlert))
593 .Times(1);
594 view.AnnounceAlert(message);
595
596 IAccessible* alert = view.AlertNode();
597 VARIANT self{.vt = VT_I4, .lVal = CHILDID_SELF};
598 BSTR strptr;
599 alert->get_accName(self, &strptr);
600 EXPECT_EQ(message, strptr);
601
602 alert->get_accDescription(self, &strptr);
603 EXPECT_EQ(message, strptr);
604
605 alert->get_accValue(self, &strptr);
606 EXPECT_EQ(message, strptr);
607
608 VARIANT role;
609 alert->get_accRole(self, &role);
610 EXPECT_EQ(role.vt, VT_I4);
611 EXPECT_EQ(role.lVal, ROLE_SYSTEM_ALERT);
612 }
613
614 TEST_F(FlutterWindowTest, LifecycleFocusMessages) {
615 MockFlutterWindow win32window;
616 EXPECT_CALL(win32window, GetWindowHandle)
617 .WillRepeatedly(Return(reinterpret_cast<HWND>(1)));
618 MockWindowBindingHandlerDelegate delegate;
619
620 WindowStateEvent last_event;
621 EXPECT_CALL(delegate, OnWindowStateEvent)
622 .WillRepeatedly([&last_event](HWND hwnd, WindowStateEvent event) {
623 last_event = event;
624 });
625 EXPECT_CALL(win32window, OnWindowStateEvent)
626 .WillRepeatedly([&](WindowStateEvent event) {
627 win32window.FlutterWindow::OnWindowStateEvent(event);
628 });
629 EXPECT_CALL(win32window, OnResize).Times(AnyNumber());
630
631 win32window.SetView(&delegate);
632
633 win32window.InjectWindowMessage(WM_SIZE, 0, 0);
634 EXPECT_EQ(last_event, WindowStateEvent::kHide);
635
636 win32window.InjectWindowMessage(WM_SIZE, 0, MAKEWORD(1, 1));
637 EXPECT_EQ(last_event, WindowStateEvent::kShow);
638
639 EXPECT_CALL(delegate, OnFocus(Eq(FlutterViewFocusState::kFocused),
640 Eq(FlutterViewFocusDirection::kUndefined)))
641 .Times(1);
642 win32window.InjectWindowMessage(WM_SETFOCUS, 0, 0);
643 EXPECT_EQ(last_event, WindowStateEvent::kFocus);
644
645 EXPECT_CALL(delegate, OnFocus(Eq(FlutterViewFocusState::kUnfocused),
646 Eq(FlutterViewFocusDirection::kUndefined)))
647 .Times(1);
648 win32window.InjectWindowMessage(WM_KILLFOCUS, 0, 0);
649 EXPECT_EQ(last_event, WindowStateEvent::kUnfocus);
650 }
651
652 TEST_F(FlutterWindowTest, CachedLifecycleMessage) {
653 MockFlutterWindow win32window;
654 EXPECT_CALL(win32window, GetWindowHandle)
655 .WillRepeatedly(Return(reinterpret_cast<HWND>(1)));
656 EXPECT_CALL(win32window, OnWindowStateEvent)
657 .WillRepeatedly([&](WindowStateEvent event) {
658 win32window.FlutterWindow::OnWindowStateEvent(event);
659 });
660 EXPECT_CALL(win32window, OnResize).Times(1);
661
662 // Restore
663 win32window.InjectWindowMessage(WM_SIZE, 0, MAKEWORD(1, 1));
664
665 // Focus
666 win32window.InjectWindowMessage(WM_SETFOCUS, 0, 0);
667
668 MockWindowBindingHandlerDelegate delegate;
669 bool focused = false;
670 bool restored = false;
671 EXPECT_CALL(delegate, OnWindowStateEvent)
672 .WillRepeatedly([&](HWND hwnd, WindowStateEvent event) {
673 if (event == WindowStateEvent::kFocus) {
674 focused = true;
675 } else if (event == WindowStateEvent::kShow) {
676 restored = true;
677 }
678 });
679
680 EXPECT_CALL(delegate, OnFocus(Eq(FlutterViewFocusState::kFocused),
681 Eq(FlutterViewFocusDirection::kUndefined)))
682 .Times(1);
683 win32window.SetView(&delegate);
684 EXPECT_TRUE(focused);
685 EXPECT_TRUE(restored);
686 }
687
688 } // namespace testing
689 } // namespace flutter
flutter::FlutterWindow
Definition: flutter_window.h:38
flutter::FlutterWindow::OnPointerMove
virtual void OnPointerMove(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, uint32_t rotation, uint32_t pressure, int modifiers_state)
Definition: flutter_window.cc:168
flutter::FlutterWindow::OnPointerLeave
virtual void OnPointerLeave(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id)
Definition: flutter_window.cc:208
flutter::FlutterWindow::OnBitmapSurfaceUpdated
virtual bool OnBitmapSurfaceUpdated(const void *allocation, size_t row_bytes, size_t height) override
Definition: flutter_window.cc:283
flutter::FlutterWindow::OnPointerDown
virtual void OnPointerDown(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, UINT button, uint32_t rotation, uint32_t pressure)
Definition: flutter_window.cc:179
flutter::FlutterWindow::OnPointerUp
virtual void OnPointerUp(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, UINT button)
Definition: flutter_window.cc:195
flutter::FlutterWindow::SetView
virtual void SetView(WindowBindingHandlerDelegate *view) override
Definition: flutter_window.cc:117
flutter::FlutterWindow::GetDpiScale
virtual float GetDpiScale() override
Definition: flutter_window.cc:130
flutter::FlutterWindowsView::FlutterWindowsView
FlutterWindowsView(FlutterViewId view_id, FlutterWindowsEngine *engine, std::unique_ptr< WindowBindingHandler > window_binding, bool is_sized_to_content, const BoxConstraints &box_constraints, FlutterWindowsViewSizingDelegate *sizing_delegate=nullptr, std::shared_ptr< WindowsProcTable > windows_proc_table=nullptr)
Definition: flutter_windows_view.cc:110
flutter::testing::MockFlutterWindowsView::MOCK_METHOD
MOCK_METHOD(void, NotifyWinEventWrapper,(ui::AXPlatformNodeWin *, ax::mojom::Event),(override))
flutter::testing::MockFlutterWindowsView::MockFlutterWindowsView
MockFlutterWindowsView(FlutterWindowsEngine *engine, std::unique_ptr< WindowBindingHandler > wbh)
Definition: flutter_windows_engine_unittests.cc:770
flutter_window.h
message
Win32Message message
Definition: keyboard_unittests.cc:137
flutter::testing::TEST_F
TEST_F(AccessibilityPluginTest, DirectAnnounceCall)
Definition: accessibility_plugin_unittests.cc:102
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::WindowStateEvent
WindowStateEvent
An event representing a change in window state that may update the.
Definition: windows_lifecycle_manager.h:24
flutter::WindowStateEvent::kHide
@ kHide
flutter::WindowStateEvent::kUnfocus
@ kUnfocus
flutter::WindowStateEvent::kShow
@ kShow
flutter::WindowStateEvent::kFocus
@ kFocus
flutter::kImplicitViewId
constexpr FlutterViewId kImplicitViewId
Definition: flutter_windows_engine.h:56
flutter::AccessibilityMode::IAccessible
@ IAccessible