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"
16 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"
23 constexpr std::chrono::milliseconds kWindowResizeTimeout{100};
31 bool SurfaceWillUpdate(
size_t cur_width,
34 size_t target_height) {
37 bool non_zero_target_dims = target_height > 0 && target_width > 0;
39 (cur_height != target_height) || (cur_width != target_width);
40 return non_zero_target_dims && not_same_size;
45 void UpdateVsync(
const FlutterWindowsEngine& engine,
46 egl::WindowSurface* surface,
48 egl::Manager* egl_manager = engine.egl_manager();
53 auto update_vsync = [egl_manager, surface, needs_vsync]() {
54 if (!surface || !surface->IsValid()) {
58 if (!surface->MakeCurrent()) {
59 FML_LOG(ERROR) <<
"Unable to make the render surface current to update "
64 if (!surface->SetVSyncEnabled(needs_vsync)) {
65 FML_LOG(ERROR) <<
"Unable to update the render surface's swap interval";
68 if (!egl_manager->render_context()->ClearCurrent()) {
69 FML_LOG(ERROR) <<
"Unable to clear current surface after updating "
79 if (engine.running()) {
80 engine.PostRasterThreadTask(update_vsync);
87 void DestroyWindowSurface(
const FlutterWindowsEngine& engine,
88 std::unique_ptr<egl::WindowSurface> surface) {
92 if (engine.running()) {
93 engine.PostRasterThreadTask(fml::MakeCopyable(
94 [surface = std::move(surface)] { surface->Destroy(); }));
107 std::unique_ptr<WindowBindingHandler> window_binding,
108 std::shared_ptr<WindowsProcTable> windows_proc_table)
111 windows_proc_table_(std::move(windows_proc_table)) {
112 if (windows_proc_table_ ==
nullptr) {
113 windows_proc_table_ = std::make_shared<WindowsProcTable>();
117 binding_handler_ = std::move(window_binding);
118 binding_handler_->SetView(
this);
127 DestroyWindowSurface(*engine_, std::move(surface_));
133 std::unique_lock<std::mutex> lock(resize_mutex_);
135 if (surface_ ==
nullptr || !surface_->IsValid()) {
139 if (resize_status_ != ResizeState::kResizeStarted) {
143 if (!ResizeRenderSurface(resize_target_height_, resize_target_width_)) {
149 resize_status_ = ResizeState::kFrameGenerated;
155 std::unique_lock<std::mutex> lock(resize_mutex_);
157 if (surface_ ==
nullptr || !surface_->IsValid()) {
161 if (resize_status_ != ResizeState::kResizeStarted) {
165 if (resize_target_width_ != width || resize_target_height_ != height) {
169 if (!ResizeRenderSurface(resize_target_width_, resize_target_height_)) {
175 resize_status_ = ResizeState::kFrameGenerated;
180 binding_handler_->UpdateFlutterCursor(cursor_name);
184 binding_handler_->SetFlutterCursor(cursor);
188 if (resize_status_ == ResizeState::kDone) {
196 std::unique_lock<std::mutex> lock(resize_mutex_);
199 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
203 if (!surface_ || !surface_->IsValid()) {
204 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
210 bool surface_will_update =
211 SurfaceWillUpdate(surface_->width(), surface_->height(), width, height);
212 if (!surface_will_update) {
213 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
217 resize_status_ = ResizeState::kResizeStarted;
218 resize_target_width_ = width;
219 resize_target_height_ = height;
221 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
226 return resize_cv_.wait_for(lock, kWindowResizeTimeout,
227 [&resize_status = resize_status_] {
228 return resize_status == ResizeState::kDone;
238 FlutterPointerDeviceKind device_kind,
240 int modifiers_state) {
242 SendPointerMove(x, y, GetOrCreatePointerState(device_kind, device_id));
248 FlutterPointerDeviceKind device_kind,
250 FlutterPointerMouseButtons flutter_button) {
251 if (flutter_button != 0) {
252 auto state = GetOrCreatePointerState(device_kind, device_id);
253 state->buttons |= flutter_button;
254 SendPointerDown(x, y, state);
261 FlutterPointerDeviceKind device_kind,
263 FlutterPointerMouseButtons flutter_button) {
264 if (flutter_button != 0) {
265 auto state = GetOrCreatePointerState(device_kind, device_id);
266 state->buttons &= ~flutter_button;
267 SendPointerUp(x, y, state);
273 FlutterPointerDeviceKind device_kind,
275 SendPointerLeave(x, y, GetOrCreatePointerState(device_kind, device_id));
280 SendPointerPanZoomStart(device_id, point.
x, point.
y);
288 SendPointerPanZoomUpdate(device_id, pan_x, pan_y, scale, rotation);
292 SendPointerPanZoomEnd(device_id);
323 SendComposeChange(
text, cursor_pos);
330 int scroll_offset_multiplier,
331 FlutterPointerDeviceKind device_kind,
333 SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier, device_kind,
339 SendScrollInertiaCancel(device_id, point.
x, point.
y);
347 if (!accessibility_bridge_) {
351 return accessibility_bridge_->GetChildOfAXFragmentRoot();
355 binding_handler_->OnCursorRectUpdated(rect);
359 binding_handler_->OnResetImeComposing();
363 void FlutterWindowsView::SendWindowMetrics(
size_t width,
365 double pixel_ratio)
const {
366 FlutterWindowMetricsEvent
event = {};
367 event.struct_size =
sizeof(event);
369 event.height = height;
370 event.pixel_ratio = pixel_ratio;
371 event.view_id = view_id_;
377 double pixel_ratio = binding_handler_->GetDpiScale();
379 FlutterWindowMetricsEvent
event = {};
380 event.struct_size =
sizeof(event);
381 event.width = bounds.
width;
382 event.height = bounds.
height;
383 event.pixel_ratio = pixel_ratio;
384 event.view_id = view_id_;
399 FlutterWindowsView::PointerState* FlutterWindowsView::GetOrCreatePointerState(
400 FlutterPointerDeviceKind device_kind,
405 int32_t pointer_id = (
static_cast<int32_t
>(device_kind) << 28) | device_id;
407 auto [it, added] = pointer_states_.try_emplace(pointer_id,
nullptr);
409 auto state = std::make_unique<PointerState>();
410 state->device_kind = device_kind;
411 state->pointer_id = pointer_id;
412 it->second = std::move(state);
415 return it->second.get();
420 void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
421 FlutterPointerEvent* event_data,
422 const PointerState* state)
const {
425 if (state->buttons == 0) {
426 event_data->phase = state->flutter_state_is_down
427 ? FlutterPointerPhase::kUp
428 : FlutterPointerPhase::kHover;
430 event_data->phase = state->flutter_state_is_down
431 ? FlutterPointerPhase::kMove
432 : FlutterPointerPhase::kDown;
436 void FlutterWindowsView::SendPointerMove(
double x,
438 PointerState* state) {
439 FlutterPointerEvent
event = {};
443 SetEventPhaseFromCursorButtonState(&event, state);
444 SendPointerEventWithData(event, state);
447 void FlutterWindowsView::SendPointerDown(
double x,
449 PointerState* state) {
450 FlutterPointerEvent
event = {};
454 SetEventPhaseFromCursorButtonState(&event, state);
455 SendPointerEventWithData(event, state);
457 state->flutter_state_is_down =
true;
460 void FlutterWindowsView::SendPointerUp(
double x,
462 PointerState* state) {
463 FlutterPointerEvent
event = {};
467 SetEventPhaseFromCursorButtonState(&event, state);
468 SendPointerEventWithData(event, state);
469 if (event.phase == FlutterPointerPhase::kUp) {
470 state->flutter_state_is_down =
false;
474 void FlutterWindowsView::SendPointerLeave(
double x,
476 PointerState* state) {
477 FlutterPointerEvent
event = {};
480 event.phase = FlutterPointerPhase::kRemove;
481 SendPointerEventWithData(event, state);
484 void FlutterWindowsView::SendPointerPanZoomStart(int32_t device_id,
488 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
489 state->pan_zoom_start_x = x;
490 state->pan_zoom_start_y = y;
491 FlutterPointerEvent
event = {};
494 event.phase = FlutterPointerPhase::kPanZoomStart;
495 SendPointerEventWithData(event, state);
498 void FlutterWindowsView::SendPointerPanZoomUpdate(int32_t device_id,
504 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
505 FlutterPointerEvent
event = {};
506 event.x = state->pan_zoom_start_x;
507 event.y = state->pan_zoom_start_y;
511 event.rotation = rotation;
512 event.phase = FlutterPointerPhase::kPanZoomUpdate;
513 SendPointerEventWithData(event, state);
516 void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) {
518 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
519 FlutterPointerEvent
event = {};
520 event.x = state->pan_zoom_start_x;
521 event.y = state->pan_zoom_start_y;
522 event.phase = FlutterPointerPhase::kPanZoomEnd;
523 SendPointerEventWithData(event, state);
526 void FlutterWindowsView::SendText(
const std::u16string&
text) {
530 void FlutterWindowsView::SendKey(
int key,
542 engine->text_input_plugin()->KeyboardHook(
551 void FlutterWindowsView::SendComposeBegin() {
555 void FlutterWindowsView::SendComposeCommit() {
559 void FlutterWindowsView::SendComposeEnd() {
563 void FlutterWindowsView::SendComposeChange(
const std::u16string&
text,
568 void FlutterWindowsView::SendScroll(
double x,
572 int scroll_offset_multiplier,
573 FlutterPointerDeviceKind device_kind,
575 auto state = GetOrCreatePointerState(device_kind, device_id);
577 FlutterPointerEvent
event = {};
580 event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll;
581 event.scroll_delta_x = delta_x * scroll_offset_multiplier;
582 event.scroll_delta_y = delta_y * scroll_offset_multiplier;
583 SetEventPhaseFromCursorButtonState(&event, state);
584 SendPointerEventWithData(event, state);
587 void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id,
591 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
593 FlutterPointerEvent
event = {};
597 FlutterPointerSignalKind::kFlutterPointerSignalKindScrollInertiaCancel;
598 SetEventPhaseFromCursorButtonState(&event, state);
599 SendPointerEventWithData(event, state);
602 void FlutterWindowsView::SendPointerEventWithData(
603 const FlutterPointerEvent& event_data,
604 PointerState* state) {
607 if (!state->flutter_state_is_added &&
608 event_data.phase != FlutterPointerPhase::kAdd) {
609 FlutterPointerEvent
event = {};
610 event.phase = FlutterPointerPhase::kAdd;
611 event.x = event_data.x;
612 event.y = event_data.y;
614 SendPointerEventWithData(event, state);
619 if (state->flutter_state_is_added &&
620 event_data.phase == FlutterPointerPhase::kAdd) {
624 FlutterPointerEvent
event = event_data;
625 event.device_kind = state->device_kind;
626 event.device = state->pointer_id;
627 event.buttons = state->buttons;
628 event.view_id = view_id_;
631 event.struct_size =
sizeof(event);
633 std::chrono::duration_cast<std::chrono::microseconds>(
634 std::chrono::high_resolution_clock::now().time_since_epoch())
639 if (event_data.phase == FlutterPointerPhase::kAdd) {
640 state->flutter_state_is_added =
true;
641 }
else if (event_data.phase == FlutterPointerPhase::kRemove) {
642 auto it = pointer_states_.find(state->pointer_id);
643 if (it != pointer_states_.end()) {
644 pointer_states_.erase(it);
651 std::unique_lock<std::mutex> lock(resize_mutex_);
653 switch (resize_status_) {
654 case ResizeState::kResizeStarted:
665 case ResizeState::kFrameGenerated: {
668 resize_status_ = ResizeState::kDone;
670 resize_cv_.notify_all();
674 windows_proc_table_->DwmFlush();
676 case ResizeState::kDone:
682 return binding_handler_->OnBitmapSurfaceCleared();
688 return binding_handler_->OnBitmapSurfaceUpdated(allocation, row_bytes,
701 FML_DCHECK(surface_ ==
nullptr);
708 UpdateVsync(*engine_, surface_.get(), NeedsVsync());
710 resize_target_width_ = bounds.
width;
711 resize_target_height_ = bounds.
height;
715 bool FlutterWindowsView::ResizeRenderSurface(
size_t width,
size_t height) {
716 FML_DCHECK(surface_ !=
nullptr);
719 if (width == surface_->width() && height == surface_->height()) {
723 auto const existing_vsync = surface_->vsync_enabled();
728 if (!surface_->Destroy()) {
729 FML_LOG(ERROR) <<
"View resize failed to destroy surface";
733 std::unique_ptr<egl::WindowSurface> resized_surface =
736 if (!resized_surface) {
737 FML_LOG(ERROR) <<
"View resize failed to create surface";
741 if (!resized_surface->MakeCurrent() ||
742 !resized_surface->SetVSyncEnabled(existing_vsync)) {
746 FML_LOG(ERROR) <<
"View resize failed to set vsync";
749 surface_ = std::move(resized_surface);
754 return surface_.get();
762 return binding_handler_->GetWindowHandle();
770 auto alert_delegate = binding_handler_->GetAlertDelegate();
771 if (!alert_delegate) {
774 alert_delegate->SetText(fml::WideStringToUtf16(
text));
775 ui::AXPlatformNodeWin* alert_node = binding_handler_->GetAlert();
780 ax::mojom::Event event) {
782 node->NotifyAccessibilityEvent(event);
787 return accessibility_bridge_.get();
791 return binding_handler_->GetAlert();
794 std::shared_ptr<AccessibilityBridgeWindows>
796 return std::make_shared<AccessibilityBridgeWindows>(
this);
800 if (semantics_enabled_ != enabled) {
801 semantics_enabled_ = enabled;
803 if (!semantics_enabled_ && accessibility_bridge_) {
804 accessibility_bridge_.reset();
805 }
else if (semantics_enabled_ && !accessibility_bridge_) {
812 UpdateVsync(*engine_, surface_.get(), NeedsVsync());
819 bool FlutterWindowsView::NeedsVsync()
const {
823 return !windows_proc_table_->DwmIsCompositionEnabled();