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