9 #include "flutter/common/constants.h"
10 #include "flutter/fml/platform/win/wstring_conversion.h"
14 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"
21 constexpr std::chrono::milliseconds kWindowResizeTimeout{100};
29 bool SurfaceWillUpdate(
size_t cur_width,
32 size_t target_height) {
35 bool non_zero_target_dims = target_height > 0 && target_width > 0;
37 (cur_height != target_height) || (cur_width != target_width);
38 return non_zero_target_dims && not_same_size;
43 void UpdateVsync(
const FlutterWindowsEngine& engine,
bool needs_vsync) {
44 AngleSurfaceManager* surface_manager = engine.surface_manager();
45 if (!surface_manager) {
54 if (engine.running()) {
55 engine.PostRasterThreadTask([surface_manager, needs_vsync]() {
56 surface_manager->SetVSyncEnabled(needs_vsync);
59 surface_manager->SetVSyncEnabled(needs_vsync);
62 if (!surface_manager->ClearCurrent()) {
64 <<
"Unable to clear current surface after updating the swap interval";
73 std::unique_ptr<WindowBindingHandler> window_binding,
74 std::shared_ptr<WindowsProcTable> windows_proc_table)
75 : windows_proc_table_(std::move(windows_proc_table)) {
76 if (windows_proc_table_ ==
nullptr) {
77 windows_proc_table_ = std::make_shared<WindowsProcTable>();
81 binding_handler_ = std::move(window_binding);
82 binding_handler_->SetView(
this);
96 FML_DCHECK(engine_ ==
nullptr);
97 FML_DCHECK(engine !=
nullptr);
106 binding_handler_->GetDpiScale());
111 std::unique_lock<std::mutex> lock(resize_mutex_);
113 if (resize_status_ != ResizeState::kResizeStarted) {
117 if (resize_target_width_ == width && resize_target_height_ == height) {
122 resize_status_ = ResizeState::kFrameGenerated;
129 binding_handler_->UpdateFlutterCursor(cursor_name);
133 binding_handler_->SetFlutterCursor(cursor);
137 if (resize_status_ == ResizeState::kDone) {
145 std::unique_lock<std::mutex> lock(resize_mutex_);
148 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
152 EGLint surface_width, surface_height;
156 bool surface_will_update =
157 SurfaceWillUpdate(surface_width, surface_height, width, height);
158 if (surface_will_update) {
159 resize_status_ = ResizeState::kResizeStarted;
160 resize_target_width_ = width;
161 resize_target_height_ = height;
164 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
166 if (surface_will_update) {
170 resize_cv_.wait_for(lock, kWindowResizeTimeout,
171 [&resize_status = resize_status_] {
172 return resize_status == ResizeState::kDone;
183 FlutterPointerDeviceKind device_kind,
185 int modifiers_state) {
187 SendPointerMove(x, y, GetOrCreatePointerState(device_kind, device_id));
193 FlutterPointerDeviceKind device_kind,
195 FlutterPointerMouseButtons flutter_button) {
196 if (flutter_button != 0) {
197 auto state = GetOrCreatePointerState(device_kind, device_id);
198 state->buttons |= flutter_button;
199 SendPointerDown(x, y, state);
206 FlutterPointerDeviceKind device_kind,
208 FlutterPointerMouseButtons flutter_button) {
209 if (flutter_button != 0) {
210 auto state = GetOrCreatePointerState(device_kind, device_id);
211 state->buttons &= ~flutter_button;
212 SendPointerUp(x, y, state);
218 FlutterPointerDeviceKind device_kind,
220 SendPointerLeave(x, y, GetOrCreatePointerState(device_kind, device_id));
225 SendPointerPanZoomStart(device_id, point.
x, point.
y);
233 SendPointerPanZoomUpdate(device_id, pan_x, pan_y, scale, rotation);
237 SendPointerPanZoomEnd(device_id);
268 SendComposeChange(
text, cursor_pos);
275 int scroll_offset_multiplier,
276 FlutterPointerDeviceKind device_kind,
278 SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier, device_kind,
284 SendScrollInertiaCancel(device_id, point.
x, point.
y);
292 if (!accessibility_bridge_) {
296 return accessibility_bridge_->GetChildOfAXFragmentRoot();
300 binding_handler_->OnCursorRectUpdated(rect);
304 binding_handler_->OnResetImeComposing();
308 void FlutterWindowsView::SendWindowMetrics(
size_t width,
310 double dpiScale)
const {
311 FlutterWindowMetricsEvent
event = {};
312 event.struct_size =
sizeof(event);
314 event.height = height;
315 event.pixel_ratio = dpiScale;
323 binding_handler_->GetDpiScale());
326 FlutterWindowsView::PointerState* FlutterWindowsView::GetOrCreatePointerState(
327 FlutterPointerDeviceKind device_kind,
332 int32_t pointer_id = (
static_cast<int32_t
>(device_kind) << 28) | device_id;
334 auto [it, added] = pointer_states_.try_emplace(pointer_id,
nullptr);
336 auto state = std::make_unique<PointerState>();
337 state->device_kind = device_kind;
338 state->pointer_id = pointer_id;
339 it->second = std::move(state);
342 return it->second.get();
347 void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
348 FlutterPointerEvent* event_data,
349 const PointerState* state)
const {
352 if (state->buttons == 0) {
353 event_data->phase = state->flutter_state_is_down
354 ? FlutterPointerPhase::kUp
355 : FlutterPointerPhase::kHover;
357 event_data->phase = state->flutter_state_is_down
358 ? FlutterPointerPhase::kMove
359 : FlutterPointerPhase::kDown;
363 void FlutterWindowsView::SendPointerMove(
double x,
365 PointerState* state) {
366 FlutterPointerEvent
event = {};
370 SetEventPhaseFromCursorButtonState(&event, state);
371 SendPointerEventWithData(event, state);
374 void FlutterWindowsView::SendPointerDown(
double x,
376 PointerState* state) {
377 FlutterPointerEvent
event = {};
381 SetEventPhaseFromCursorButtonState(&event, state);
382 SendPointerEventWithData(event, state);
384 state->flutter_state_is_down =
true;
387 void FlutterWindowsView::SendPointerUp(
double x,
389 PointerState* state) {
390 FlutterPointerEvent
event = {};
394 SetEventPhaseFromCursorButtonState(&event, state);
395 SendPointerEventWithData(event, state);
396 if (event.phase == FlutterPointerPhase::kUp) {
397 state->flutter_state_is_down =
false;
401 void FlutterWindowsView::SendPointerLeave(
double x,
403 PointerState* state) {
404 FlutterPointerEvent
event = {};
407 event.phase = FlutterPointerPhase::kRemove;
408 SendPointerEventWithData(event, state);
411 void FlutterWindowsView::SendPointerPanZoomStart(int32_t device_id,
415 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
416 state->pan_zoom_start_x = x;
417 state->pan_zoom_start_y = y;
418 FlutterPointerEvent
event = {};
421 event.phase = FlutterPointerPhase::kPanZoomStart;
422 SendPointerEventWithData(event, state);
425 void FlutterWindowsView::SendPointerPanZoomUpdate(int32_t device_id,
431 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
432 FlutterPointerEvent
event = {};
433 event.x = state->pan_zoom_start_x;
434 event.y = state->pan_zoom_start_y;
438 event.rotation = rotation;
439 event.phase = FlutterPointerPhase::kPanZoomUpdate;
440 SendPointerEventWithData(event, state);
443 void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) {
445 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
446 FlutterPointerEvent
event = {};
447 event.x = state->pan_zoom_start_x;
448 event.y = state->pan_zoom_start_y;
449 event.phase = FlutterPointerPhase::kPanZoomEnd;
450 SendPointerEventWithData(event, state);
453 void FlutterWindowsView::SendText(
const std::u16string&
text) {
457 void FlutterWindowsView::SendKey(
int key,
475 void FlutterWindowsView::SendComposeBegin() {
479 void FlutterWindowsView::SendComposeCommit() {
483 void FlutterWindowsView::SendComposeEnd() {
487 void FlutterWindowsView::SendComposeChange(
const std::u16string&
text,
492 void FlutterWindowsView::SendScroll(
double x,
496 int scroll_offset_multiplier,
497 FlutterPointerDeviceKind device_kind,
499 auto state = GetOrCreatePointerState(device_kind, device_id);
501 FlutterPointerEvent
event = {};
504 event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll;
505 event.scroll_delta_x = delta_x * scroll_offset_multiplier;
506 event.scroll_delta_y = delta_y * scroll_offset_multiplier;
507 SetEventPhaseFromCursorButtonState(&event, state);
508 SendPointerEventWithData(event, state);
511 void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id,
515 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
517 FlutterPointerEvent
event = {};
521 FlutterPointerSignalKind::kFlutterPointerSignalKindScrollInertiaCancel;
522 SetEventPhaseFromCursorButtonState(&event, state);
523 SendPointerEventWithData(event, state);
526 void FlutterWindowsView::SendPointerEventWithData(
527 const FlutterPointerEvent& event_data,
528 PointerState* state) {
531 if (!state->flutter_state_is_added &&
532 event_data.phase != FlutterPointerPhase::kAdd) {
533 FlutterPointerEvent
event = {};
534 event.phase = FlutterPointerPhase::kAdd;
535 event.x = event_data.x;
536 event.y = event_data.y;
538 SendPointerEventWithData(event, state);
543 if (state->flutter_state_is_added &&
544 event_data.phase == FlutterPointerPhase::kAdd) {
548 FlutterPointerEvent
event = event_data;
549 event.device_kind = state->device_kind;
550 event.device = state->pointer_id;
551 event.buttons = state->buttons;
555 event.view_id = flutter::kFlutterImplicitViewId;
558 event.struct_size =
sizeof(event);
560 std::chrono::duration_cast<std::chrono::microseconds>(
561 std::chrono::high_resolution_clock::now().time_since_epoch())
566 if (event_data.phase == FlutterPointerPhase::kAdd) {
567 state->flutter_state_is_added =
true;
568 }
else if (event_data.phase == FlutterPointerPhase::kRemove) {
569 auto it = pointer_states_.find(state->pointer_id);
570 if (it != pointer_states_.end()) {
571 pointer_states_.erase(it);
578 std::unique_lock<std::mutex> lock(resize_mutex_);
580 switch (resize_status_) {
584 case ResizeState::kResizeStarted:
586 case ResizeState::kFrameGenerated: {
587 bool visible = binding_handler_->IsVisible();
588 bool swap_buffers_result;
596 resize_status_ = ResizeState::kDone;
598 resize_cv_.notify_all();
602 windows_proc_table_->DwmFlush();
607 return swap_buffers_result;
609 case ResizeState::kDone:
618 return binding_handler_->OnBitmapSurfaceUpdated(allocation, row_bytes,
628 UpdateVsync(*engine_, NeedsVsync());
630 resize_target_width_ = bounds.
width;
631 resize_target_height_ = bounds.
height;
646 return binding_handler_->GetWindowHandle();
654 auto alert_delegate = binding_handler_->GetAlertDelegate();
655 if (!alert_delegate) {
658 alert_delegate->SetText(fml::WideStringToUtf16(
text));
659 ui::AXPlatformNodeWin* alert_node = binding_handler_->GetAlert();
664 ax::mojom::Event event) {
666 node->NotifyAccessibilityEvent(event);
671 return accessibility_bridge_.get();
675 return binding_handler_->GetAlert();
678 std::shared_ptr<AccessibilityBridgeWindows>
680 return std::make_shared<AccessibilityBridgeWindows>(
this);
684 if (semantics_enabled_ != enabled) {
685 semantics_enabled_ = enabled;
687 if (!semantics_enabled_ && accessibility_bridge_) {
688 accessibility_bridge_.reset();
689 }
else if (semantics_enabled_ && !accessibility_bridge_) {
696 UpdateVsync(*engine_, NeedsVsync());
705 bool FlutterWindowsView::NeedsVsync()
const {
709 return !windows_proc_table_->DwmIsCompositionEnabled();