9 #include "flutter/fml/platform/win/wstring_conversion.h"
13 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"
20 constexpr std::chrono::milliseconds kWindowResizeTimeout{100};
28 bool SurfaceWillUpdate(
size_t cur_width,
31 size_t target_height) {
34 bool non_zero_target_dims = target_height > 0 && target_width > 0;
36 (cur_height != target_height) || (cur_width != target_width);
37 return non_zero_target_dims && not_same_size;
42 std::unique_ptr<WindowBindingHandler> window_binding) {
44 binding_handler_ = std::move(window_binding);
45 binding_handler_->SetView(
this);
47 render_target_ = std::make_unique<WindowsRenderTarget>(
48 binding_handler_->GetRenderTarget());
62 std::unique_ptr<FlutterWindowsEngine> engine) {
63 engine_ = std::move(engine);
65 engine_->SetView(
this);
70 binding_handler_->GetDpiScale());
75 std::unique_lock<std::mutex> lock(resize_mutex_);
77 if (resize_status_ != ResizeState::kResizeStarted) {
81 if (resize_target_width_ == width && resize_target_height_ == height) {
84 engine_->surface_manager()->ResizeSurface(
GetRenderTarget(), width, height,
85 binding_handler_->NeedsVSync());
86 resize_status_ = ResizeState::kFrameGenerated;
93 binding_handler_->UpdateFlutterCursor(cursor_name);
97 binding_handler_->SetFlutterCursor(cursor);
101 if (resize_status_ == ResizeState::kDone) {
103 engine_->ScheduleFrame();
109 std::unique_lock<std::mutex> lock(resize_mutex_);
111 if (!engine_->surface_manager()) {
112 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
116 EGLint surface_width, surface_height;
117 engine_->surface_manager()->GetSurfaceDimensions(&surface_width,
120 bool surface_will_update =
121 SurfaceWillUpdate(surface_width, surface_height, width, height);
122 if (surface_will_update) {
123 resize_status_ = ResizeState::kResizeStarted;
124 resize_target_width_ = width;
125 resize_target_height_ = height;
128 SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
130 if (surface_will_update) {
134 resize_cv_.wait_for(lock, kWindowResizeTimeout,
135 [&resize_status = resize_status_] {
136 return resize_status == ResizeState::kDone;
147 FlutterPointerDeviceKind device_kind,
149 int modifiers_state) {
150 engine_->keyboard_key_handler()->SyncModifiersIfNeeded(modifiers_state);
151 SendPointerMove(x, y, GetOrCreatePointerState(device_kind, device_id));
157 FlutterPointerDeviceKind device_kind,
159 FlutterPointerMouseButtons flutter_button) {
160 if (flutter_button != 0) {
161 auto state = GetOrCreatePointerState(device_kind, device_id);
162 state->buttons |= flutter_button;
163 SendPointerDown(x, y, state);
170 FlutterPointerDeviceKind device_kind,
172 FlutterPointerMouseButtons flutter_button) {
173 if (flutter_button != 0) {
174 auto state = GetOrCreatePointerState(device_kind, device_id);
175 state->buttons &= ~flutter_button;
176 SendPointerUp(x, y, state);
182 FlutterPointerDeviceKind device_kind,
184 SendPointerLeave(x, y, GetOrCreatePointerState(device_kind, device_id));
189 SendPointerPanZoomStart(device_id, point.
x, point.
y);
197 SendPointerPanZoomUpdate(device_id, pan_x, pan_y, scale, rotation);
201 SendPointerPanZoomEnd(device_id);
232 SendComposeChange(
text, cursor_pos);
239 int scroll_offset_multiplier,
240 FlutterPointerDeviceKind device_kind,
242 SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier, device_kind,
248 SendScrollInertiaCancel(device_id, point.
x, point.
y);
252 engine_->UpdateSemanticsEnabled(enabled);
256 if (!accessibility_bridge_) {
260 return accessibility_bridge_->GetChildOfAXFragmentRoot();
264 binding_handler_->OnCursorRectUpdated(rect);
268 binding_handler_->OnResetImeComposing();
272 void FlutterWindowsView::SendWindowMetrics(
size_t width,
274 double dpiScale)
const {
275 FlutterWindowMetricsEvent
event = {};
276 event.struct_size =
sizeof(event);
278 event.height = height;
279 event.pixel_ratio = dpiScale;
280 engine_->SendWindowMetricsEvent(event);
287 binding_handler_->GetDpiScale());
290 FlutterWindowsView::PointerState* FlutterWindowsView::GetOrCreatePointerState(
291 FlutterPointerDeviceKind device_kind,
296 int32_t pointer_id = (
static_cast<int32_t
>(device_kind) << 28) | device_id;
298 auto [it, added] = pointer_states_.try_emplace(pointer_id,
nullptr);
300 auto state = std::make_unique<PointerState>();
301 state->device_kind = device_kind;
302 state->pointer_id = pointer_id;
303 it->second = std::move(state);
306 return it->second.get();
311 void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
312 FlutterPointerEvent* event_data,
313 const PointerState* state)
const {
316 if (state->buttons == 0) {
317 event_data->phase = state->flutter_state_is_down
318 ? FlutterPointerPhase::kUp
319 : FlutterPointerPhase::kHover;
321 event_data->phase = state->flutter_state_is_down
322 ? FlutterPointerPhase::kMove
323 : FlutterPointerPhase::kDown;
327 void FlutterWindowsView::SendPointerMove(
double x,
329 PointerState* state) {
330 FlutterPointerEvent
event = {};
334 SetEventPhaseFromCursorButtonState(&event, state);
335 SendPointerEventWithData(event, state);
338 void FlutterWindowsView::SendPointerDown(
double x,
340 PointerState* state) {
341 FlutterPointerEvent
event = {};
345 SetEventPhaseFromCursorButtonState(&event, state);
346 SendPointerEventWithData(event, state);
348 state->flutter_state_is_down =
true;
351 void FlutterWindowsView::SendPointerUp(
double x,
353 PointerState* state) {
354 FlutterPointerEvent
event = {};
358 SetEventPhaseFromCursorButtonState(&event, state);
359 SendPointerEventWithData(event, state);
360 if (event.phase == FlutterPointerPhase::kUp) {
361 state->flutter_state_is_down =
false;
365 void FlutterWindowsView::SendPointerLeave(
double x,
367 PointerState* state) {
368 FlutterPointerEvent
event = {};
371 event.phase = FlutterPointerPhase::kRemove;
372 SendPointerEventWithData(event, state);
375 void FlutterWindowsView::SendPointerPanZoomStart(int32_t device_id,
379 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
380 state->pan_zoom_start_x = x;
381 state->pan_zoom_start_y = y;
382 FlutterPointerEvent
event = {};
385 event.phase = FlutterPointerPhase::kPanZoomStart;
386 SendPointerEventWithData(event, state);
389 void FlutterWindowsView::SendPointerPanZoomUpdate(int32_t device_id,
395 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
396 FlutterPointerEvent
event = {};
397 event.x = state->pan_zoom_start_x;
398 event.y = state->pan_zoom_start_y;
402 event.rotation = rotation;
403 event.phase = FlutterPointerPhase::kPanZoomUpdate;
404 SendPointerEventWithData(event, state);
407 void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) {
409 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
410 FlutterPointerEvent
event = {};
411 event.x = state->pan_zoom_start_x;
412 event.y = state->pan_zoom_start_y;
413 event.phase = FlutterPointerPhase::kPanZoomEnd;
414 SendPointerEventWithData(event, state);
417 void FlutterWindowsView::SendText(
const std::u16string&
text) {
418 engine_->text_input_plugin()->TextHook(
text);
421 void FlutterWindowsView::SendKey(
int key,
428 engine_->keyboard_key_handler()->KeyboardHook(
432 engine_->text_input_plugin()->KeyboardHook(
439 void FlutterWindowsView::SendComposeBegin() {
440 engine_->text_input_plugin()->ComposeBeginHook();
443 void FlutterWindowsView::SendComposeCommit() {
444 engine_->text_input_plugin()->ComposeCommitHook();
447 void FlutterWindowsView::SendComposeEnd() {
448 engine_->text_input_plugin()->ComposeEndHook();
451 void FlutterWindowsView::SendComposeChange(
const std::u16string&
text,
453 engine_->text_input_plugin()->ComposeChangeHook(
text, cursor_pos);
456 void FlutterWindowsView::SendScroll(
double x,
460 int scroll_offset_multiplier,
461 FlutterPointerDeviceKind device_kind,
463 auto state = GetOrCreatePointerState(device_kind, device_id);
465 FlutterPointerEvent
event = {};
468 event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll;
469 event.scroll_delta_x = delta_x * scroll_offset_multiplier;
470 event.scroll_delta_y = delta_y * scroll_offset_multiplier;
471 SetEventPhaseFromCursorButtonState(&event, state);
472 SendPointerEventWithData(event, state);
475 void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id,
479 GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id);
481 FlutterPointerEvent
event = {};
485 FlutterPointerSignalKind::kFlutterPointerSignalKindScrollInertiaCancel;
486 SetEventPhaseFromCursorButtonState(&event, state);
487 SendPointerEventWithData(event, state);
490 void FlutterWindowsView::SendPointerEventWithData(
491 const FlutterPointerEvent& event_data,
492 PointerState* state) {
495 if (!state->flutter_state_is_added &&
496 event_data.phase != FlutterPointerPhase::kAdd) {
497 FlutterPointerEvent
event = {};
498 event.phase = FlutterPointerPhase::kAdd;
499 event.x = event_data.x;
500 event.y = event_data.y;
502 SendPointerEventWithData(event, state);
507 if (state->flutter_state_is_added &&
508 event_data.phase == FlutterPointerPhase::kAdd) {
512 FlutterPointerEvent
event = event_data;
513 event.device_kind = state->device_kind;
514 event.device = state->pointer_id;
515 event.buttons = state->buttons;
518 event.struct_size =
sizeof(event);
520 std::chrono::duration_cast<std::chrono::microseconds>(
521 std::chrono::high_resolution_clock::now().time_since_epoch())
524 engine_->SendPointerEvent(event);
526 if (event_data.phase == FlutterPointerPhase::kAdd) {
527 state->flutter_state_is_added =
true;
528 }
else if (event_data.phase == FlutterPointerPhase::kRemove) {
529 auto it = pointer_states_.find(state->pointer_id);
530 if (it != pointer_states_.end()) {
531 pointer_states_.erase(it);
537 return engine_->surface_manager()->MakeCurrent();
541 return engine_->surface_manager()->MakeResourceCurrent();
545 return engine_->surface_manager()->ClearContext();
550 std::unique_lock<std::mutex> lock(resize_mutex_);
552 switch (resize_status_) {
556 case ResizeState::kResizeStarted:
558 case ResizeState::kFrameGenerated: {
559 bool visible = binding_handler_->IsVisible();
560 bool swap_buffers_result;
566 swap_buffers_result = engine_->surface_manager()->SwapBuffers();
568 resize_status_ = ResizeState::kDone;
570 resize_cv_.notify_all();
571 binding_handler_->OnWindowResized();
573 swap_buffers_result = engine_->surface_manager()->SwapBuffers();
575 return swap_buffers_result;
577 case ResizeState::kDone:
579 return engine_->surface_manager()->SwapBuffers();
586 return binding_handler_->OnBitmapSurfaceUpdated(allocation, row_bytes,
591 if (engine_ && engine_->surface_manager()) {
593 bool enable_vsync = binding_handler_->NeedsVSync();
595 bounds.
height, enable_vsync);
601 engine_->surface_manager()->ClearCurrent();
603 resize_target_width_ = bounds.
width;
604 resize_target_height_ = bounds.
height;
609 if (engine_ && engine_->surface_manager()) {
610 engine_->surface_manager()->DestroySurface();
615 binding_handler_->SendInitialAccessibilityFeatures();
619 engine_->UpdateHighContrastEnabled(enabled);
623 return render_target_.get();
627 return binding_handler_->GetPlatformWindow();
631 return engine_.get();
635 auto alert_delegate = binding_handler_->GetAlertDelegate();
636 if (!alert_delegate) {
639 alert_delegate->SetText(fml::WideStringToUtf16(
text));
640 ui::AXPlatformNodeWin* alert_node = binding_handler_->GetAlert();
645 ax::mojom::Event event) {
647 node->NotifyAccessibilityEvent(event);
652 return accessibility_bridge_.get();
656 return binding_handler_->GetAlert();
659 std::shared_ptr<AccessibilityBridgeWindows>
661 return std::make_shared<AccessibilityBridgeWindows>(
this);
665 if (semantics_enabled_ != enabled) {
666 semantics_enabled_ = enabled;
668 if (!semantics_enabled_ && accessibility_bridge_) {
669 accessibility_bridge_.reset();
670 }
else if (semantics_enabled_ && !accessibility_bridge_) {
678 if (!surface_manager) {
685 auto needs_vsync = binding_handler_->NeedsVSync();
686 engine_->PostRasterThreadTask([surface_manager, needs_vsync]() {
689 <<
"Unable to make surface current to update the swap interval";
699 engine_->OnWindowStateEvent(hwnd, event);