| Flutter Windows Embedder |

flutter_windows_view.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
5 #include "flutter/shell/platform/windows/flutter_windows_view.h"
6
7 #include <chrono>
8
9 #include "flutter/common/constants.h"
10 #include "flutter/fml/make_copyable.h"
11 #include "flutter/fml/platform/win/wstring_conversion.h"
12 #include "flutter/fml/synchronization/waitable_event.h"
13 #include "flutter/shell/platform/common/accessibility_bridge.h"
14 #include "flutter/shell/platform/windows/keyboard_key_channel_handler.h"
15 #include "flutter/shell/platform/windows/text_input_plugin.h"
16 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"
17
18 namespace flutter {
19
20 namespace {
21 // The maximum duration to block the Windows event loop while waiting
22 // for a window resize operation to complete.
23 constexpr std::chrono::milliseconds kWindowResizeTimeout{100};
24
25 /// Returns true if the surface will be updated as part of the resize process.
26 ///
27 /// This is called on window resize to determine if the platform thread needs
28 /// to be blocked until the frame with the right size has been rendered. It
29 /// should be kept in-sync with how the engine deals with a new surface request
30 /// as seen in `CreateOrUpdateSurface` in `GPUSurfaceGL`.
31 bool SurfaceWillUpdate(size_t cur_width,
32 size_t cur_height,
33 size_t target_width,
34 size_t target_height) {
35 // TODO (https://github.com/flutter/flutter/issues/65061) : Avoid special
36 // handling for zero dimensions.
37 bool non_zero_target_dims = target_height > 0 && target_width > 0;
38 bool not_same_size =
39 (cur_height != target_height) || (cur_width != target_width);
40 return non_zero_target_dims && not_same_size;
41 }
42
43 /// Update the surface's swap interval to block until the v-blank iff
44 /// the system compositor is disabled.
45 void UpdateVsync(const FlutterWindowsEngine& engine,
46 egl::WindowSurface* surface,
47 bool needs_vsync) {
48 egl::Manager* egl_manager = engine.egl_manager();
49 if (!egl_manager) {
50 return;
51 }
52
53 auto update_vsync = [egl_manager, surface, needs_vsync]() {
54 if (!surface || !surface->IsValid()) {
55 return;
56 }
57
58 if (!surface->MakeCurrent()) {
59 FML_LOG(ERROR) << "Unable to make the render surface current to update "
60 "the swap interval";
61 return;
62 }
63
64 if (!surface->SetVSyncEnabled(needs_vsync)) {
65 FML_LOG(ERROR) << "Unable to update the render surface's swap interval";
66 }
67
68 if (!egl_manager->render_context()->ClearCurrent()) {
69 FML_LOG(ERROR) << "Unable to clear current surface after updating "
70 "the swap interval";
71 }
72 };
73
74 // Updating the vsync makes the EGL context and render surface current.
75 // If the engine is running, the render surface should only be made current on
76 // the raster thread. If the engine is initializing, the raster thread doesn't
77 // exist yet and the render surface can be made current on the platform
78 // thread.
79 if (engine.running()) {
80 engine.PostRasterThreadTask(update_vsync);
81 } else {
82 update_vsync();
83 }
84 }
85
86 /// Destroys a rendering surface that backs a Flutter view.
87 void DestroyWindowSurface(const FlutterWindowsEngine& engine,
88 std::unique_ptr<egl::WindowSurface> surface) {
89 // EGL surfaces are used on the raster thread if the engine is running.
90 // There may be pending raster tasks that use this surface. Destroy the
91 // surface on the raster thread to avoid concurrent uses.
92 if (engine.running()) {
93 engine.PostRasterThreadTask(fml::MakeCopyable(
94 [surface = std::move(surface)] { surface->Destroy(); }));
95 } else {
96 // There's no raster thread if engine isn't running. The surface can be
97 // destroyed on the platform thread.
98 surface->Destroy();
99 }
100 }
101
102 } // namespace
103
104 FlutterWindowsView::FlutterWindowsView(
105 FlutterViewId view_id,
106 FlutterWindowsEngine* engine,
107 std::unique_ptr<WindowBindingHandler> window_binding,
108 bool is_sized_to_content,
109 const BoxConstraints& box_constraints,
110 FlutterWindowsViewSizingDelegate* sizing_delegate,
111 std::shared_ptr<WindowsProcTable> windows_proc_table)
112 : view_id_(view_id),
113 engine_(engine),
114 is_sized_to_content_(is_sized_to_content),
115 box_constraints_(box_constraints),
116 sizing_delegate_(sizing_delegate),
117 windows_proc_table_(std::move(windows_proc_table)) {
118 if (windows_proc_table_ == nullptr) {
119 windows_proc_table_ = std::make_shared<WindowsProcTable>();
120 }
121
122 // Take the binding handler, and give it a pointer back to self.
123 binding_handler_ = std::move(window_binding);
124 binding_handler_->SetView(this);
125 }
126
127 FlutterWindowsView::~FlutterWindowsView() {
128 // The view owns the child window.
129 // Notify the engine the view's child window will no longer be visible.
130 engine_->OnWindowStateEvent(GetWindowHandle(), WindowStateEvent::kHide);
131
132 if (surface_) {
133 DestroyWindowSurface(*engine_, std::move(surface_));
134 }
135 }
136
137 bool FlutterWindowsView::OnEmptyFrameGenerated() {
138 // Called on the raster thread.
139 std::unique_lock<std::mutex> lock(resize_mutex_);
140
141 if (surface_ == nullptr || !surface_->IsValid()) {
142 return false;
143 }
144
145 if (resize_status_ != ResizeState::kResizeStarted) {
146 return true;
147 }
148
149 if (!ResizeRenderSurface(resize_target_height_, resize_target_width_)) {
150 return false;
151 }
152
153 // Platform thread is blocked for the entire duration until the
154 // resize_status_ is set to kDone by |OnFramePresented|.
155 resize_status_ = ResizeState::kFrameGenerated;
156 return true;
157 }
158
159 bool FlutterWindowsView::OnFrameGenerated(size_t width, size_t height) {
160 // Called on the raster thread.
161 std::unique_lock<std::mutex> lock(resize_mutex_);
162
163 if (IsSizedToContent()) {
164 if (!ResizeRenderSurface(width, height)) {
165 return false;
166 }
167
168 sizing_delegate_->DidUpdateViewSize(width, height);
169 return true;
170 }
171
172 if (surface_ == nullptr || !surface_->IsValid()) {
173 return false;
174 }
175
176 if (resize_status_ != ResizeState::kResizeStarted) {
177 return true;
178 }
179
180 if (resize_target_width_ != width || resize_target_height_ != height) {
181 return false;
182 }
183
184 if (!ResizeRenderSurface(resize_target_width_, resize_target_height_)) {
185 return false;
186 }
187
188 // Platform thread is blocked for the entire duration until the
189 // resize_status_ is set to kDone by |OnFramePresented|.
190 resize_status_ = ResizeState::kFrameGenerated;
191 return true;
192 }
193
194 void FlutterWindowsView::ForceRedraw() {
195 if (resize_status_ == ResizeState::kDone) {
196 // Request new frame.
197 engine_->ScheduleFrame();
198 }
199 }
200
201 // Called on the platform thread.
202 bool FlutterWindowsView::OnWindowSizeChanged(size_t width, size_t height) {
203 if (IsSizedToContent()) {
204 // No resize synchronization needed for views sized to content.
205 return true;
206 }
207
208 if (!engine_->egl_manager()) {
209 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
210 return true;
211 }
212
213 if (!surface_ || !surface_->IsValid()) {
214 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
215 return true;
216 }
217
218 // We're using OpenGL rendering. Resizing the surface must happen on the
219 // raster thread.
220 bool surface_will_update =
221 SurfaceWillUpdate(surface_->width(), surface_->height(), width, height);
222 if (!surface_will_update) {
223 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
224 return true;
225 }
226
227 {
228 std::unique_lock<std::mutex> lock(resize_mutex_);
229 resize_status_ = ResizeState::kResizeStarted;
230 resize_target_width_ = width;
231 resize_target_height_ = height;
232 }
233
234 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
235
236 std::chrono::time_point<std::chrono::steady_clock> start_time =
237 std::chrono::steady_clock::now();
238
239 while (true) {
240 if (std::chrono::steady_clock::now() > start_time + kWindowResizeTimeout) {
241 return false;
242 }
243 std::unique_lock<std::mutex> lock(resize_mutex_);
244 if (resize_status_ == ResizeState::kDone) {
245 break;
246 }
247 lock.unlock();
248 engine_->task_runner()->PollOnce(kWindowResizeTimeout);
249 }
250 return true;
251 }
252
253 void FlutterWindowsView::OnWindowRepaint() {
254 ForceRedraw();
255 }
256
257 void FlutterWindowsView::OnPointerMove(double x,
258 double y,
259 FlutterPointerDeviceKind device_kind,
260 int32_t device_id,
261 int modifiers_state) {
262 engine_->keyboard_key_handler()->SyncModifiersIfNeeded(modifiers_state);
263 SendPointerMove(x, y, GetOrCreatePointerState(device_kind, device_id));
264 }
265
266 void FlutterWindowsView::OnPointerDown(
267 double x,
268 double y,
269 FlutterPointerDeviceKind device_kind,
270 int32_t device_id,
271 FlutterPointerMouseButtons flutter_button) {
272 if (flutter_button != 0) {
273 auto state = GetOrCreatePointerState(device_kind, device_id);
274 state->buttons |= flutter_button;
275 SendPointerDown(x, y, state);
276 }
277 }
278
279 void FlutterWindowsView::OnPointerUp(
280 double x,
281 double y,
282 FlutterPointerDeviceKind device_kind,
283 int32_t device_id,
284 FlutterPointerMouseButtons flutter_button) {
285 if (flutter_button != 0) {
286 auto state = GetOrCreatePointerState(device_kind, device_id);
287 state->buttons &= ~flutter_button;
288 SendPointerUp(x, y, state);
289 }
290 }
291
292 void FlutterWindowsView::OnPointerLeave(double x,
293 double y,
294 FlutterPointerDeviceKind device_kind,
295 int32_t device_id) {
296 SendPointerLeave(x, y, GetOrCreatePointerState(device_kind, device_id));
297 }
298
299 void FlutterWindowsView::OnPointerPanZoomStart(int32_t device_id) {
300 PointerLocation point = binding_handler_->GetPrimaryPointerLocation();
301 SendPointerPanZoomStart(device_id, point.x, point.y);
302 }
303
304 void FlutterWindowsView::OnPointerPanZoomUpdate(int32_t device_id,
305 double pan_x,
306 double pan_y,
307 double scale,
308 double rotation) {
309 SendPointerPanZoomUpdate(device_id, pan_x, pan_y, scale, rotation);
310 }
311
312 void FlutterWindowsView::OnPointerPanZoomEnd(int32_t device_id) {
313 SendPointerPanZoomEnd(device_id);
314 }
315
316 void FlutterWindowsView::OnText(const std::u16string& text) {
317 SendText(text);
318 }
319
320 void FlutterWindowsView::OnKey(int key,
321 int scancode,
322 int action,
323 char32_t character,
324 bool extended,
325 bool was_down,
326 KeyEventCallback callback) {
327 SendKey(key, scancode, action, character, extended, was_down, callback);
328 }
329
330 void FlutterWindowsView::OnFocus(FlutterViewFocusState focus_state,
331 FlutterViewFocusDirection direction) {
332 SendFocus(focus_state, direction);
333 }
334
335 void FlutterWindowsView::OnComposeBegin() {
336 SendComposeBegin();
337 }
338
339 void FlutterWindowsView::OnComposeCommit() {
340 SendComposeCommit();
341 }
342
343 void FlutterWindowsView::OnComposeEnd() {
344 SendComposeEnd();
345 }
346
347 void FlutterWindowsView::OnComposeChange(const std::u16string& text,
348 int cursor_pos) {
349 SendComposeChange(text, cursor_pos);
350 }
351
352 void FlutterWindowsView::OnScroll(double x,
353 double y,
354 double delta_x,
355 double delta_y,
356 int scroll_offset_multiplier,
357 FlutterPointerDeviceKind device_kind,
358 int32_t device_id) {
359 SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier, device_kind,
360 device_id);
361 }
362
363 void FlutterWindowsView::OnScrollInertiaCancel(int32_t device_id) {
364 PointerLocation point = binding_handler_->GetPrimaryPointerLocation();
365 SendScrollInertiaCancel(device_id, point.x, point.y);
366 }
367
368 void FlutterWindowsView::OnUpdateSemanticsEnabled(bool enabled) {
369 engine_->UpdateSemanticsEnabled(enabled);
370 }
371
372 gfx::NativeViewAccessible FlutterWindowsView::GetNativeViewAccessible() {
373 if (!accessibility_bridge_) {
374 return nullptr;
375 }
376
377 return accessibility_bridge_->GetChildOfAXFragmentRoot();
378 }
379
380 void FlutterWindowsView::OnCursorRectUpdated(const Rect& rect) {
381 binding_handler_->OnCursorRectUpdated(rect);
382 }
383
384 void FlutterWindowsView::OnResetImeComposing() {
385 binding_handler_->OnResetImeComposing();
386 }
387
388 // Sends new size information to FlutterEngine.
389 void FlutterWindowsView::SendWindowMetrics(size_t width,
390 size_t height,
391 double pixel_ratio) const {
392 FlutterEngineDisplayId display_id = binding_handler_->GetDisplayId();
393 FlutterWindowMetricsEvent event = {};
394 event.struct_size = sizeof(event);
395 event.width = width;
396 event.height = height;
397 event.has_constraints = true;
398 auto const constraints = GetConstraints();
399 event.min_width_constraint =
400 static_cast<size_t>(constraints.smallest().width());
401 event.min_height_constraint =
402 static_cast<size_t>(constraints.smallest().height());
403 event.max_width_constraint =
404 static_cast<size_t>(constraints.biggest().width());
405 event.max_height_constraint =
406 static_cast<size_t>(constraints.biggest().height());
407 event.pixel_ratio = pixel_ratio;
408 event.display_id = display_id;
409 event.view_id = view_id_;
410 engine_->SendWindowMetricsEvent(event);
411 }
412
413 FlutterWindowMetricsEvent FlutterWindowsView::CreateWindowMetricsEvent() const {
414 PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
415 double pixel_ratio = binding_handler_->GetDpiScale();
416 FlutterEngineDisplayId display_id = binding_handler_->GetDisplayId();
417
418 FlutterWindowMetricsEvent event = {};
419 event.struct_size = sizeof(event);
420 event.width = bounds.width;
421 event.height = bounds.height;
422 auto constraints = GetConstraints();
423 event.has_constraints = true;
424 event.min_width_constraint =
425 static_cast<size_t>(constraints.smallest().width());
426 event.min_height_constraint =
427 static_cast<size_t>(constraints.smallest().height());
428 event.max_width_constraint =
429 static_cast<size_t>(constraints.biggest().width());
430 event.max_height_constraint =
431 static_cast<size_t>(constraints.biggest().height());
432 event.pixel_ratio = pixel_ratio;
433 event.display_id = display_id;
434 event.view_id = view_id_;
435
436 return event;
437 }
438
439 void FlutterWindowsView::SendInitialBounds() {
440 // Non-implicit views' initial window metrics are sent when the view is added
441 // to the engine.
442 if (!IsImplicitView()) {
443 return;
444 }
445
446 engine_->SendWindowMetricsEvent(CreateWindowMetricsEvent());
447 }
448
449 FlutterWindowsView::PointerState* FlutterWindowsView::GetOrCreatePointerState(
450 FlutterPointerDeviceKind device_kind,
451 int32_t device_id) {
452 // Create a virtual pointer ID that is unique across all device types
453 // to prevent pointers from clashing in the engine's converter
454 // (lib/ui/window/pointer_data_packet_converter.cc)
455 int32_t pointer_id = (static_cast<int32_t>(device_kind) << 28) | device_id;
456
457 auto [it, added] = pointer_states_.try_emplace(pointer_id, nullptr);
458 if (added) {
459 auto state = std::make_unique<PointerState>();
460 state->device_kind = device_kind;
461 state->pointer_id = pointer_id;
462 it->second = std::move(state);
463 }
464
465 return it->second.get();
466 }
467
468 // Set's |event_data|'s phase to either kMove or kHover depending on the current
469 // primary mouse button state.
470 void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
471 FlutterPointerEvent* event_data,
472 const PointerState* state) const {
473 // For details about this logic, see FlutterPointerPhase in the embedder.h
474 // file.
475 if (state->buttons == 0) {
476 event_data->phase = state->flutter_state_is_down
477 ? FlutterPointerPhase::kUp
478 : FlutterPointerPhase::kHover;
479 } else {
480 event_data->phase = state->flutter_state_is_down
481 ? FlutterPointerPhase::kMove
482 : FlutterPointerPhase::kDown;
483 }
484 }
485
486 void FlutterWindowsView::SendPointerMove(double x,
487 double y,
488 PointerState* state) {
489 FlutterPointerEvent event = {};
490 event.x = x;
491 event.y = y;
492
493 SetEventPhaseFromCursorButtonState(&event, state);
494 SendPointerEventWithData(event, state);
495 }
496
497 void FlutterWindowsView::SendPointerDown(double x,
498 double y,
499 PointerState* state) {
500 FlutterPointerEvent event = {};
501 event.x = x;
502 event.y = y;
503
504 SetEventPhaseFromCursorButtonState(&event, state);
505 SendPointerEventWithData(event, state);
506
507 state->flutter_state_is_down = true;
508 }
509
510 void FlutterWindowsView::SendPointerUp(double x,
511 double y,
512 PointerState* state) {
513 FlutterPointerEvent event = {};
514 event.x = x;
515 event.y = y;
516
517 SetEventPhaseFromCursorButtonState(&event, state);
518 SendPointerEventWithData(event, state);
519 if (event.phase == FlutterPointerPhase::kUp) {
520 state->flutter_state_is_down = false;
521 }
522 }
523
524 void FlutterWindowsView::SendPointerLeave(double x,
525 double y,
526 PointerState* state) {
527 FlutterPointerEvent event = {};
528 event.x = x;
529 event.y = y;
530 event.phase = FlutterPointerPhase::kRemove;
531 SendPointerEventWithData(event, state);
532 }
533
534 void FlutterWindowsView::SendPointerPanZoomStart(int32_t device_id,
535 double x,
536 double y) {
537 auto state =
538 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
539 state->pan_zoom_start_x = x;
540 state->pan_zoom_start_y = y;
541 FlutterPointerEvent event = {};
542 event.x = x;
543 event.y = y;
544 event.phase = FlutterPointerPhase::kPanZoomStart;
545 SendPointerEventWithData(event, state);
546 }
547
548 void FlutterWindowsView::SendPointerPanZoomUpdate(int32_t device_id,
549 double pan_x,
550 double pan_y,
551 double scale,
552 double rotation) {
553 auto state =
554 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
555 FlutterPointerEvent event = {};
556 event.x = state->pan_zoom_start_x;
557 event.y = state->pan_zoom_start_y;
558 event.pan_x = pan_x;
559 event.pan_y = pan_y;
560 event.scale = scale;
561 event.rotation = rotation;
562 event.phase = FlutterPointerPhase::kPanZoomUpdate;
563 SendPointerEventWithData(event, state);
564 }
565
566 void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) {
567 auto state =
568 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
569 FlutterPointerEvent event = {};
570 event.x = state->pan_zoom_start_x;
571 event.y = state->pan_zoom_start_y;
572 event.phase = FlutterPointerPhase::kPanZoomEnd;
573 SendPointerEventWithData(event, state);
574 }
575
576 void FlutterWindowsView::SendText(const std::u16string& text) {
577 engine_->text_input_plugin()->TextHook(text);
578 }
579
580 void FlutterWindowsView::SendKey(int key,
581 int scancode,
582 int action,
583 char32_t character,
584 bool extended,
585 bool was_down,
586 KeyEventCallback callback) {
587 engine_->keyboard_key_handler()->KeyboardHook(
588 key, scancode, action, character, extended, was_down,
589 [engine = engine_, view_id = view_id_, key, scancode, action, character,
590 extended, was_down, callback = std::move(callback)](bool handled) {
591 if (!handled) {
592 engine->text_input_plugin()->KeyboardHook(
593 key, scancode, action, character, extended, was_down);
594 }
595 if (engine->view(view_id)) {
596 callback(handled);
597 }
598 });
599 }
600
601 void FlutterWindowsView::SendFocus(FlutterViewFocusState focus_state,
602 FlutterViewFocusDirection direction) {
603 FlutterViewFocusEvent event = {};
604 event.struct_size = sizeof(event);
605 event.view_id = view_id_;
606 event.state = focus_state;
607 event.direction = direction;
608 engine_->SendViewFocusEvent(event);
609 }
610
611 void FlutterWindowsView::SendComposeBegin() {
612 engine_->text_input_plugin()->ComposeBeginHook();
613 }
614
615 void FlutterWindowsView::SendComposeCommit() {
616 engine_->text_input_plugin()->ComposeCommitHook();
617 }
618
619 void FlutterWindowsView::SendComposeEnd() {
620 engine_->text_input_plugin()->ComposeEndHook();
621 }
622
623 void FlutterWindowsView::SendComposeChange(const std::u16string& text,
624 int cursor_pos) {
625 engine_->text_input_plugin()->ComposeChangeHook(text, cursor_pos);
626 }
627
628 void FlutterWindowsView::SendScroll(double x,
629 double y,
630 double delta_x,
631 double delta_y,
632 int scroll_offset_multiplier,
633 FlutterPointerDeviceKind device_kind,
634 int32_t device_id) {
635 auto state = GetOrCreatePointerState(device_kind, device_id);
636
637 FlutterPointerEvent event = {};
638 event.x = x;
639 event.y = y;
640 event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll;
641 event.scroll_delta_x = delta_x * scroll_offset_multiplier;
642 event.scroll_delta_y = delta_y * scroll_offset_multiplier;
643 SetEventPhaseFromCursorButtonState(&event, state);
644 SendPointerEventWithData(event, state);
645 }
646
647 void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id,
648 double x,
649 double y) {
650 auto state =
651 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
652
653 FlutterPointerEvent event = {};
654 event.x = x;
655 event.y = y;
656 event.signal_kind =
657 FlutterPointerSignalKind::kFlutterPointerSignalKindScrollInertiaCancel;
658 SetEventPhaseFromCursorButtonState(&event, state);
659 SendPointerEventWithData(event, state);
660 }
661
662 void FlutterWindowsView::SendPointerEventWithData(
663 const FlutterPointerEvent& event_data,
664 PointerState* state) {
665 // If sending anything other than an add, and the pointer isn't already added,
666 // synthesize an add to satisfy Flutter's expectations about events.
667 if (!state->flutter_state_is_added &&
668 event_data.phase != FlutterPointerPhase::kAdd) {
669 FlutterPointerEvent event = {};
670 event.phase = FlutterPointerPhase::kAdd;
671 event.x = event_data.x;
672 event.y = event_data.y;
673 event.buttons = 0;
674 SendPointerEventWithData(event, state);
675 }
676
677 // Don't double-add (e.g., if events are delivered out of order, so an add has
678 // already been synthesized).
679 if (state->flutter_state_is_added &&
680 event_data.phase == FlutterPointerPhase::kAdd) {
681 return;
682 }
683
684 FlutterPointerEvent event = event_data;
685 event.device_kind = state->device_kind;
686 event.device = state->pointer_id;
687 event.buttons = state->buttons;
688 event.view_id = view_id_;
689
690 // Set metadata that's always the same regardless of the event.
691 event.struct_size = sizeof(event);
692 event.timestamp =
693 std::chrono::duration_cast<std::chrono::microseconds>(
694 std::chrono::high_resolution_clock::now().time_since_epoch())
695 .count();
696
697 engine_->SendPointerEvent(event);
698
699 if (event_data.phase == FlutterPointerPhase::kAdd) {
700 state->flutter_state_is_added = true;
701 } else if (event_data.phase == FlutterPointerPhase::kRemove) {
702 auto it = pointer_states_.find(state->pointer_id);
703 if (it != pointer_states_.end()) {
704 pointer_states_.erase(it);
705 }
706 }
707 }
708
709 void FlutterWindowsView::OnFramePresented() {
710 // Called on the engine's raster thread.
711 std::unique_lock<std::mutex> lock(resize_mutex_);
712
713 switch (resize_status_) {
714 case ResizeState::kResizeStarted:
715 // The caller must first call |OnFrameGenerated| or
716 // |OnEmptyFrameGenerated| before calling this method. This
717 // indicates one of the following:
718 //
719 // 1. The caller did not call these methods.
720 // 2. The caller ignored these methods' result.
721 // 3. The platform thread started a resize after the caller called these
722 // methods. We might have presented a frame of the wrong size to the
723 // view.
724 return;
725 case ResizeState::kFrameGenerated: {
726 // A frame was generated for a pending resize.
727 resize_status_ = ResizeState::kDone;
728 // Unblock the platform thread.
729 engine_->task_runner()->PostTask([this] {});
730
731 lock.unlock();
732
733 // Blocking the raster thread until DWM flushes alleviates glitches where
734 // previous size surface is stretched over current size view.
735 windows_proc_table_->DwmFlush();
736 }
737 case ResizeState::kDone:
738 return;
739 }
740 }
741
742 bool FlutterWindowsView::ClearSoftwareBitmap() {
743 return binding_handler_->OnBitmapSurfaceCleared();
744 }
745
746 bool FlutterWindowsView::PresentSoftwareBitmap(const void* allocation,
747 size_t row_bytes,
748 size_t height) {
749 return binding_handler_->OnBitmapSurfaceUpdated(allocation, row_bytes,
750 height);
751 }
752
753 FlutterViewId FlutterWindowsView::view_id() const {
754 return view_id_;
755 }
756
757 bool FlutterWindowsView::IsImplicitView() const {
758 return view_id_ == kImplicitViewId;
759 }
760
761 void FlutterWindowsView::CreateRenderSurface() {
762 FML_DCHECK(surface_ == nullptr);
763
764 if (engine_->egl_manager()) {
765 PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
766 surface_ = engine_->egl_manager()->CreateWindowSurface(
767 GetWindowHandle(), bounds.width, bounds.height);
768
769 UpdateVsync(*engine_, surface_.get(), NeedsVsync());
770
771 resize_target_width_ = bounds.width;
772 resize_target_height_ = bounds.height;
773 }
774 }
775
776 bool FlutterWindowsView::ResizeRenderSurface(size_t width, size_t height) {
777 FML_DCHECK(surface_ != nullptr);
778
779 // No-op if the surface is already the desired size.
780 if (width == surface_->width() && height == surface_->height()) {
781 return true;
782 }
783
784 auto const existing_vsync = surface_->vsync_enabled();
785
786 // TODO: Destroying the surface and re-creating it is expensive.
787 // Ideally this would use ANGLE's automatic surface sizing instead.
788 // See: https://github.com/flutter/flutter/issues/79427
789 if (!surface_->Destroy()) {
790 FML_LOG(ERROR) << "View resize failed to destroy surface";
791 return false;
792 }
793
794 std::unique_ptr<egl::WindowSurface> resized_surface =
795 engine_->egl_manager()->CreateWindowSurface(GetWindowHandle(), width,
796 height);
797 if (!resized_surface) {
798 FML_LOG(ERROR) << "View resize failed to create surface";
799 return false;
800 }
801
802 if (!resized_surface->MakeCurrent() ||
803 !resized_surface->SetVSyncEnabled(existing_vsync)) {
804 // Surfaces block until the v-blank by default.
805 // Failing to update the vsync might result in unnecessary blocking.
806 // This regresses performance but not correctness.
807 FML_LOG(ERROR) << "View resize failed to set vsync";
808 }
809
810 surface_ = std::move(resized_surface);
811 return true;
812 }
813
814 egl::WindowSurface* FlutterWindowsView::surface() const {
815 return surface_.get();
816 }
817
818 void FlutterWindowsView::OnHighContrastChanged() {
819 engine_->UpdateHighContrastMode();
820 }
821
822 HWND FlutterWindowsView::GetWindowHandle() const {
823 return binding_handler_->GetWindowHandle();
824 }
825
826 FlutterWindowsEngine* FlutterWindowsView::GetEngine() const {
827 return engine_;
828 }
829
830 void FlutterWindowsView::AnnounceAlert(const std::wstring& text) {
831 auto alert_delegate = binding_handler_->GetAlertDelegate();
832 if (!alert_delegate) {
833 return;
834 }
835 alert_delegate->SetText(fml::WideStringToUtf16(text));
836 ui::AXPlatformNodeWin* alert_node = binding_handler_->GetAlert();
837 NotifyWinEventWrapper(alert_node, ax::mojom::Event::kAlert);
838 }
839
840 void FlutterWindowsView::NotifyWinEventWrapper(ui::AXPlatformNodeWin* node,
841 ax::mojom::Event event) {
842 if (node) {
843 node->NotifyAccessibilityEvent(event);
844 }
845 }
846
847 ui::AXFragmentRootDelegateWin* FlutterWindowsView::GetAxFragmentRootDelegate() {
848 return accessibility_bridge_.get();
849 }
850
851 ui::AXPlatformNodeWin* FlutterWindowsView::AlertNode() const {
852 return binding_handler_->GetAlert();
853 }
854
855 std::shared_ptr<AccessibilityBridgeWindows>
856 FlutterWindowsView::CreateAccessibilityBridge() {
857 return std::make_shared<AccessibilityBridgeWindows>(this);
858 }
859
860 void FlutterWindowsView::UpdateSemanticsEnabled(bool enabled) {
861 if (semantics_enabled_ != enabled) {
862 semantics_enabled_ = enabled;
863
864 if (!semantics_enabled_ && accessibility_bridge_) {
865 accessibility_bridge_.reset();
866 } else if (semantics_enabled_ && !accessibility_bridge_) {
867 accessibility_bridge_ = CreateAccessibilityBridge();
868 }
869 }
870 }
871
872 void FlutterWindowsView::OnDwmCompositionChanged() {
873 UpdateVsync(*engine_, surface_.get(), NeedsVsync());
874 }
875
876 void FlutterWindowsView::OnWindowStateEvent(HWND hwnd, WindowStateEvent event) {
877 engine_->OnWindowStateEvent(hwnd, event);
878 }
879
880 bool FlutterWindowsView::Focus() {
881 return binding_handler_->Focus();
882 }
883
884 bool FlutterWindowsView::NeedsVsync() const {
885 // If the Desktop Window Manager composition is enabled,
886 // the system itself synchronizes with vsync.
887 // See: https://learn.microsoft.com/windows/win32/dwm/composition-ovw
888 return !windows_proc_table_->DwmIsCompositionEnabled();
889 }
890
891 bool FlutterWindowsView::IsSizedToContent() const {
892 return is_sized_to_content_;
893 }
894
895 BoxConstraints FlutterWindowsView::GetConstraints() const {
896 if (!is_sized_to_content_) {
897 PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
898 return BoxConstraints(Size(bounds.width, bounds.height),
899 Size(bounds.width, bounds.height));
900 }
901
902 Size smallest = box_constraints_.smallest();
903 Size biggest = box_constraints_.biggest();
904 if (sizing_delegate_) {
905 auto const work_area = sizing_delegate_->GetWorkArea();
906 double const width = std::min(static_cast<double>(work_area.width),
907 box_constraints_.biggest().width());
908 double const height = std::min(static_cast<double>(work_area.height),
909 box_constraints_.biggest().height());
910 biggest = Size(width, height);
911 }
912 return BoxConstraints(smallest, biggest);
913 }
914
915 } // namespace flutter
accessibility_bridge.h
flutter::FlutterWindowsEngine
Definition: flutter_windows_engine.h:92
flutter::FlutterWindowsEngine::UpdateHighContrastMode
void UpdateHighContrastMode()
Definition: flutter_windows_engine.cc:1025
flutter::FlutterWindowsEngine::task_runner
TaskRunner * task_runner()
Definition: flutter_windows_engine.h:173
flutter::FlutterWindowsEngine::OnWindowStateEvent
void OnWindowStateEvent(HWND hwnd, WindowStateEvent event)
Definition: flutter_windows_engine.cc:1069
flutter::FlutterWindowsEngine::SendViewFocusEvent
void SendViewFocusEvent(const FlutterViewFocusEvent &event)
Definition: flutter_windows_engine.cc:744
flutter::FlutterWindowsEngine::UpdateSemanticsEnabled
void UpdateSemanticsEnabled(bool enabled)
Definition: flutter_windows_engine.cc:990
flutter::FlutterWindowsEngine::keyboard_key_handler
KeyboardHandlerBase * keyboard_key_handler()
Definition: flutter_windows_engine.h:203
flutter::FlutterWindowsEngine::ScheduleFrame
void ScheduleFrame()
Definition: flutter_windows_engine.cc:810
flutter::FlutterWindowsEngine::text_input_plugin
TextInputPlugin * text_input_plugin()
Definition: flutter_windows_engine.h:206
flutter::FlutterWindowsEngine::SendPointerEvent
void SendPointerEvent(const FlutterPointerEvent &event)
Definition: flutter_windows_engine.cc:730
flutter::FlutterWindowsEngine::SendWindowMetricsEvent
void SendWindowMetricsEvent(const FlutterWindowMetricsEvent &event)
Definition: flutter_windows_engine.cc:723
flutter::FlutterWindowsEngine::egl_manager
egl::Manager * egl_manager() const
Definition: flutter_windows_engine.h:183
flutter::FlutterWindowsView::OnFramePresented
virtual void OnFramePresented()
Definition: flutter_windows_view.cc:709
flutter::FlutterWindowsView::OnPointerPanZoomStart
virtual void OnPointerPanZoomStart(int32_t device_id) override
Definition: flutter_windows_view.cc:299
flutter::FlutterWindowsView::CreateRenderSurface
void CreateRenderSurface()
Definition: flutter_windows_view.cc:761
flutter::FlutterWindowsView::OnPointerUp
void OnPointerUp(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, FlutterPointerMouseButtons button) override
Definition: flutter_windows_view.cc:279
flutter::FlutterWindowsView::Focus
virtual bool Focus()
Definition: flutter_windows_view.cc:880
flutter::FlutterWindowsView::UpdateSemanticsEnabled
virtual void UpdateSemanticsEnabled(bool enabled)
Definition: flutter_windows_view.cc:860
flutter::FlutterWindowsView::GetAxFragmentRootDelegate
virtual ui::AXFragmentRootDelegateWin * GetAxFragmentRootDelegate() override
Definition: flutter_windows_view.cc:847
flutter::FlutterWindowsView::OnPointerMove
void OnPointerMove(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, int modifiers_state) override
Definition: flutter_windows_view.cc:257
flutter::FlutterWindowsView::IsImplicitView
bool IsImplicitView() const
Definition: flutter_windows_view.cc:757
flutter::FlutterWindowsView::OnScrollInertiaCancel
void OnScrollInertiaCancel(int32_t device_id) override
Definition: flutter_windows_view.cc:363
flutter::FlutterWindowsView::CreateAccessibilityBridge
virtual std::shared_ptr< AccessibilityBridgeWindows > CreateAccessibilityBridge()
Definition: flutter_windows_view.cc:856
flutter::FlutterWindowsView::OnComposeBegin
void OnComposeBegin() override
Definition: flutter_windows_view.cc:335
flutter::FlutterWindowsView::AlertNode
ui::AXPlatformNodeWin * AlertNode() const
Definition: flutter_windows_view.cc:851
flutter::FlutterWindowsView::OnResetImeComposing
virtual void OnResetImeComposing()
Definition: flutter_windows_view.cc:384
flutter::FlutterWindowsView::OnUpdateSemanticsEnabled
virtual void OnUpdateSemanticsEnabled(bool enabled) override
Definition: flutter_windows_view.cc:368
flutter::FlutterWindowsView::OnPointerLeave
void OnPointerLeave(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id=0) override
Definition: flutter_windows_view.cc:292
flutter::FlutterWindowsView::NotifyWinEventWrapper
virtual void NotifyWinEventWrapper(ui::AXPlatformNodeWin *node, ax::mojom::Event event)
Definition: flutter_windows_view.cc:840
flutter::FlutterWindowsView::GetEngine
FlutterWindowsEngine * GetEngine() const
Definition: flutter_windows_view.cc:826
flutter::FlutterWindowsView::OnScroll
void OnScroll(double x, double y, double delta_x, double delta_y, int scroll_offset_multiplier, FlutterPointerDeviceKind device_kind, int32_t device_id) override
Definition: flutter_windows_view.cc:352
flutter::FlutterWindowsView::OnWindowStateEvent
void OnWindowStateEvent(HWND hwnd, WindowStateEvent event) override
Definition: flutter_windows_view.cc:876
flutter::FlutterWindowsView::OnPointerPanZoomEnd
virtual void OnPointerPanZoomEnd(int32_t device_id) override
Definition: flutter_windows_view.cc:312
flutter::FlutterWindowsView::CreateWindowMetricsEvent
FlutterWindowMetricsEvent CreateWindowMetricsEvent() const
Definition: flutter_windows_view.cc:413
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:104
flutter::FlutterWindowsView::view_id
FlutterViewId view_id() const
Definition: flutter_windows_view.cc:753
flutter::FlutterWindowsView::AnnounceAlert
virtual void AnnounceAlert(const std::wstring &text)
Definition: flutter_windows_view.cc:830
flutter::FlutterWindowsView::SendInitialBounds
void SendInitialBounds()
Definition: flutter_windows_view.cc:439
flutter::FlutterWindowsView::PresentSoftwareBitmap
virtual bool PresentSoftwareBitmap(const void *allocation, size_t row_bytes, size_t height)
Definition: flutter_windows_view.cc:746
flutter::FlutterWindowsView::OnFocus
void OnFocus(FlutterViewFocusState focus_state, FlutterViewFocusDirection direction) override
Definition: flutter_windows_view.cc:330
flutter::FlutterWindowsView::GetWindowHandle
virtual HWND GetWindowHandle() const
Definition: flutter_windows_view.cc:822
flutter::FlutterWindowsView::surface
egl::WindowSurface * surface() const
Definition: flutter_windows_view.cc:814
flutter::FlutterWindowsView::OnWindowSizeChanged
bool OnWindowSizeChanged(size_t width, size_t height) override
Definition: flutter_windows_view.cc:202
flutter::FlutterWindowsView::OnText
void OnText(const std::u16string &) override
Definition: flutter_windows_view.cc:316
flutter::FlutterWindowsView::OnWindowRepaint
void OnWindowRepaint() override
Definition: flutter_windows_view.cc:253
flutter::FlutterWindowsView::OnPointerPanZoomUpdate
virtual void OnPointerPanZoomUpdate(int32_t device_id, double pan_x, double pan_y, double scale, double rotation) override
Definition: flutter_windows_view.cc:304
flutter::FlutterWindowsView::OnComposeChange
void OnComposeChange(const std::u16string &text, int cursor_pos) override
Definition: flutter_windows_view.cc:347
flutter::FlutterWindowsView::ForceRedraw
void ForceRedraw()
Definition: flutter_windows_view.cc:194
flutter::FlutterWindowsView::OnDwmCompositionChanged
void OnDwmCompositionChanged()
Definition: flutter_windows_view.cc:872
flutter::FlutterWindowsView::OnComposeCommit
void OnComposeCommit() override
Definition: flutter_windows_view.cc:339
flutter::FlutterWindowsView::ClearSoftwareBitmap
virtual bool ClearSoftwareBitmap()
Definition: flutter_windows_view.cc:742
flutter::FlutterWindowsView::OnPointerDown
void OnPointerDown(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, FlutterPointerMouseButtons button) override
Definition: flutter_windows_view.cc:266
flutter::FlutterWindowsView::GetNativeViewAccessible
virtual gfx::NativeViewAccessible GetNativeViewAccessible() override
Definition: flutter_windows_view.cc:372
flutter::FlutterWindowsView::~FlutterWindowsView
virtual ~FlutterWindowsView()
Definition: flutter_windows_view.cc:127
flutter::FlutterWindowsView::OnHighContrastChanged
void OnHighContrastChanged() override
Definition: flutter_windows_view.cc:818
flutter::FlutterWindowsView::OnCursorRectUpdated
virtual void OnCursorRectUpdated(const Rect &rect)
Definition: flutter_windows_view.cc:380
flutter::FlutterWindowsView::OnKey
void OnKey(int key, int scancode, int action, char32_t character, bool extended, bool was_down, KeyEventCallback callback) override
Definition: flutter_windows_view.cc:320
flutter::FlutterWindowsView::OnComposeEnd
void OnComposeEnd() override
Definition: flutter_windows_view.cc:343
flutter::FlutterWindowsView::OnEmptyFrameGenerated
bool OnEmptyFrameGenerated()
Definition: flutter_windows_view.cc:137
flutter::FlutterWindowsView::OnFrameGenerated
bool OnFrameGenerated(size_t width, size_t height)
Definition: flutter_windows_view.cc:159
flutter::FlutterWindowsViewSizingDelegate
Definition: flutter_windows_view.h:33
flutter::FlutterWindowsViewSizingDelegate::GetWorkArea
virtual WindowRect GetWorkArea() const =0
flutter::FlutterWindowsViewSizingDelegate::DidUpdateViewSize
virtual void DidUpdateViewSize(int32_t width, int32_t height)=0
flutter::KeyboardHandlerBase::SyncModifiersIfNeeded
virtual void SyncModifiersIfNeeded(int modifiers_state)=0
flutter::KeyboardHandlerBase::KeyboardHook
virtual void KeyboardHook(int key, int scancode, int action, char32_t character, bool extended, bool was_down, KeyEventCallback callback)=0
flutter::TaskRunner::PollOnce
void PollOnce(std::chrono::milliseconds timeout)
Definition: task_runner.cc:95
flutter::TaskRunner::PostTask
void PostTask(TaskClosure task)
Definition: task_runner.cc:88
flutter::TextInputPlugin::ComposeCommitHook
virtual void ComposeCommitHook()
Definition: text_input_plugin.cc:141
flutter::TextInputPlugin::ComposeChangeHook
virtual void ComposeChangeHook(const std::u16string &text, int cursor_pos)
Definition: text_input_plugin.cc:193
flutter::TextInputPlugin::TextHook
virtual void TextHook(const std::u16string &text)
Definition: text_input_plugin.cc:68
flutter::TextInputPlugin::ComposeEndHook
virtual void ComposeEndHook()
Definition: text_input_plugin.cc:176
flutter::TextInputPlugin::ComposeBeginHook
virtual void ComposeBeginHook()
Definition: text_input_plugin.cc:126
flutter::WindowBindingHandlerDelegate::KeyEventCallback
std::function< void(bool)> KeyEventCallback
Definition: window_binding_handler_delegate.h:20
flutter::egl::Manager::CreateWindowSurface
virtual std::unique_ptr< WindowSurface > CreateWindowSurface(HWND hwnd, size_t width, size_t height)
Definition: manager.cc:283
flutter::egl::WindowSurface
Definition: window_surface.h:19
flutter_windows_view.h
callback
FlutterDesktopBinaryReply callback
Definition: flutter_windows_view_unittests.cc:52
keyboard_key_channel_handler.h
extended
bool extended
Definition: keyboard_key_handler_unittests.cc:118
key
int key
Definition: keyboard_key_handler_unittests.cc:114
character
char32_t character
Definition: keyboard_key_handler_unittests.cc:117
action
int action
Definition: keyboard_key_handler_unittests.cc:116
scancode
int scancode
Definition: keyboard_key_handler_unittests.cc:115
was_down
bool was_down
Definition: keyboard_key_handler_unittests.cc:119
text
std::u16string text
Definition: keyboard_unittests.cc:332
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::FlutterViewId
int64_t FlutterViewId
Definition: accessibility_plugin.h:15
flutter::kImplicitViewId
constexpr FlutterViewId kImplicitViewId
Definition: flutter_windows_engine.h:56
flutter::PhysicalWindowBounds
Definition: window_binding_handler.h:28
flutter::PhysicalWindowBounds::height
size_t height
Definition: window_binding_handler.h:30
flutter::PhysicalWindowBounds::width
size_t width
Definition: window_binding_handler.h:29
flutter::PointerLocation
Definition: window_binding_handler.h:35
flutter::PointerLocation::x
size_t x
Definition: window_binding_handler.h:36
flutter::PointerLocation::y
size_t y
Definition: window_binding_handler.h:37
text_input_plugin.h