From 449ba202f0f20f0aa89b6f22422b055fed0d6612 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 22 Sep 2023 14:10:33 -0700 Subject: [PATCH 01/23] Impl --- examples/glfw_drm/FlutterEmbedderGLFW.cc | 4 ++++ lib/ui/platform_dispatcher.dart | 4 +++- lib/ui/pointer.dart | 3 ++- lib/ui/window/pointer_data.h | 5 +++-- lib/ui/window/pointer_data_packet_converter.cc | 6 +++++- lib/ui/window/pointer_data_packet_converter_unittests.cc | 1 + lib/web_ui/lib/pointer.dart | 3 ++- .../flutter/embedding/android/AndroidTouchProcessor.java | 7 +++++-- .../darwin/ios/framework/Source/FlutterViewController.mm | 4 ++++ .../macos/framework/Source/FlutterViewController.mm | 2 ++ shell/platform/embedder/embedder.h | 2 ++ shell/platform/glfw/flutter_glfw.cc | 4 ++++ shell/platform/linux/fl_engine.cc | 4 ++++ shell/platform/windows/flutter_windows_view.cc | 9 +++++++++ 14 files changed, 50 insertions(+), 8 deletions(-) diff --git a/examples/glfw_drm/FlutterEmbedderGLFW.cc b/examples/glfw_drm/FlutterEmbedderGLFW.cc index ef9435b8857a3..b759f83633882 100644 --- a/examples/glfw_drm/FlutterEmbedderGLFW.cc +++ b/examples/glfw_drm/FlutterEmbedderGLFW.cc @@ -26,6 +26,7 @@ static const size_t kInitialWindowHeight = 600; // Maximum damage history - for triple buffering we need to store damage for // last two frames; Some Android devices (Pixel 4) use quad buffering. static const int kMaxHistorySize = 10; +static constexpr int64_t kImplicitViewId = 0; // Keeps track of the most recent frame damages so that existing damage can // be easily computed. @@ -56,6 +57,9 @@ void GLFWcursorPositionCallbackAtPhase(GLFWwindow* window, std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); + // TODO(loicsharma): This assumes all pointer events are on the implicit + // view and should be updated to support multiple views. + event.view_id = 0; FlutterEngineSendPointerEvent( reinterpret_cast(glfwGetWindowUserPointer(window)), &event, 1); diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 5f42aa4af9f26..57d95e682d553 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -417,10 +417,11 @@ class PlatformDispatcher { // If this value changes, update the encoding code in the following files: // + // * pointer_data.h // * pointer_data.cc // * pointer.dart // * AndroidTouchProcessor.java - static const int _kPointerDataFieldCount = 35; + static const int _kPointerDataFieldCount = 36; static PointerDataPacket _unpackPointerDataPacket(ByteData packet) { const int kStride = Int64List.bytesPerElement; @@ -467,6 +468,7 @@ class PlatformDispatcher { panDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), scale: packet.getFloat64(kStride * offset++, _kFakeHostEndian), rotation: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + viewId: packet.getInt64(kStride * offset++, _kFakeHostEndian), )); assert(offset == (i + 1) * _kPointerDataFieldCount); } diff --git a/lib/ui/pointer.dart b/lib/ui/pointer.dart index 48d5e7dfee1b4..82c7e11f81096 100644 --- a/lib/ui/pointer.dart +++ b/lib/ui/pointer.dart @@ -419,7 +419,8 @@ class PointerData { 'panDeltaX: $panDeltaX, ' 'panDeltaY: $panDeltaY, ' 'scale: $scale, ' - 'rotation: $rotation' + 'rotation: $rotation, ' + 'viewId: $viewId ' ')'; } } diff --git a/lib/ui/window/pointer_data.h b/lib/ui/window/pointer_data.h index 1f323cc4f8169..f0693baed6c5b 100644 --- a/lib/ui/window/pointer_data.h +++ b/lib/ui/window/pointer_data.h @@ -11,7 +11,7 @@ namespace flutter { // If this value changes, update the pointer data unpacking code in // platform_dispatcher.dart. -static constexpr int kPointerDataFieldCount = 35; +static constexpr int kPointerDataFieldCount = 36; static constexpr int kBytesPerField = sizeof(int64_t); // Must match the button constants in events.dart. enum PointerButtonMouse : int64_t { @@ -32,7 +32,7 @@ enum PointerButtonStylus : int64_t { kPointerButtonStylusSecondary = 1 << 2, }; -// This structure is unpacked by hooks.dart. +// This structure is unpacked by platform_dispatcher.dart. struct alignas(8) PointerData { // Must match the PointerChange enum in pointer.dart. enum class Change : int64_t { @@ -100,6 +100,7 @@ struct alignas(8) PointerData { double pan_delta_y; double scale; double rotation; + int64_t view_id; void Clear(); }; diff --git a/lib/ui/window/pointer_data_packet_converter.cc b/lib/ui/window/pointer_data_packet_converter.cc index 6750a7da22761..b34bce30aa151 100644 --- a/lib/ui/window/pointer_data_packet_converter.cc +++ b/lib/ui/window/pointer_data_packet_converter.cc @@ -69,7 +69,11 @@ void PointerDataPacketConverter::ConvertPointerData( break; } case PointerData::Change::kAdd: { - FML_DCHECK(states_.find(pointer_data.device) == states_.end()); + // TODO(loicsharma): The macOS embedder does not share + // its mouse state across its view controllers, resulting + // in multiple pointer adds for the same pointer. + // See: https://github.com/flutter/flutter/issues/125931 + // FML_DCHECK(states_.find(pointer_data.device) == states_.end()); EnsurePointerState(pointer_data); converted_pointers.push_back(pointer_data); break; diff --git a/lib/ui/window/pointer_data_packet_converter_unittests.cc b/lib/ui/window/pointer_data_packet_converter_unittests.cc index 7c4c98162a3eb..3d6dce7571d98 100644 --- a/lib/ui/window/pointer_data_packet_converter_unittests.cc +++ b/lib/ui/window/pointer_data_packet_converter_unittests.cc @@ -129,6 +129,7 @@ void CreateSimulatedTrackpadGestureData(PointerData& data, // NOLINT data.pan_delta_y = 0.0; data.scale = scale; data.rotation = rotation; + data.view_id = 0; } void UnpackPointerPacket(std::vector& output, // NOLINT diff --git a/lib/web_ui/lib/pointer.dart b/lib/web_ui/lib/pointer.dart index 469730c371731..a14455712c4c1 100644 --- a/lib/web_ui/lib/pointer.dart +++ b/lib/web_ui/lib/pointer.dart @@ -147,7 +147,8 @@ class PointerData { 'panDeltaX: $panDeltaX, ' 'panDeltaY: $panDeltaY, ' 'scale: $scale, ' - 'rotation: $rotation' + 'rotation: $rotation, ' + 'viewId: $viewId' ')'; } } diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index f3a75a991b309..79f5de8ba7a4d 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -80,8 +80,8 @@ public class AndroidTouchProcessor { int UNKNOWN = 4; } - // Must match the unpacking code in hooks.dart. - private static final int POINTER_DATA_FIELD_COUNT = 35; + // Must match the unpacking code in platform_dispatcher.dart. + private static final int POINTER_DATA_FIELD_COUNT = 36; @VisibleForTesting static final int BYTES_PER_FIELD = 8; // Default if context is null, chosen to ensure reasonable speed scrolling. @@ -411,6 +411,9 @@ private void addPointerForIndex( packet.putDouble(0.0); // pan_delta_y packet.putDouble(1.0); // scale packet.putDouble(0.0); // rotation + // TODO(loicsharma): This assumes all pointer events are on the implicit + // view and should be updated to support multiple views. + packet.putLong(0); // view_id if (isTrackpadPan && (panZoomType == PointerChange.PAN_ZOOM_END)) { ongoingPans.remove(pointerId); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index c3223766d4c01..4f80227b44ff4 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -1176,6 +1176,10 @@ - (void)dispatchTouches:(NSSet*)touches pointer_data.device = reinterpret_cast(touch); + // TODO(loicsharma): This assumes all pointer events are on the implicit + // view and should be updated to support multiple views. + pointer_data.view_id = 0; + // Pointer will be generated in pointer_data_packet_converter.cc. pointer_data.pointer_identifier = 0; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 5c22fe6c01d71..635066def1a4c 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -780,6 +780,7 @@ - (void)dispatchMouseEvent:(NSEvent*)event phase:(FlutterPointerPhase)phase { .device_kind = deviceKind, // If a click triggered a synthesized kAdd, don't pass the buttons in that event. .buttons = phase == kAdd ? 0 : _mouseState.buttons, + .view_id = static_cast(_viewId), }; if (phase == kPanZoomUpdate) { @@ -1077,6 +1078,7 @@ - (void)touchesBeganWithEvent:(NSEvent*)event { .device = kPointerPanZoomDeviceId, .signal_kind = kFlutterPointerSignalKindScrollInertiaCancel, .device_kind = kFlutterPointerDeviceKindTrackpad, + .view_id = static_cast(_viewId), }; [_engine sendPointerEvent:flutterEvent]; diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index cfef518dcf6fe..bb20da8942c05 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -961,6 +961,8 @@ typedef struct { double scale; /// The rotation of the pan/zoom in radians, where 0.0 is the initial angle. double rotation; + /// The identifier of the view that received the pointer event. + int64_t view_id; } FlutterPointerEvent; typedef enum { diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index 554a2745baf2f..d3751555c77b2 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -14,6 +14,7 @@ #include #include +#include "flutter/common/constants.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" #include "flutter/shell/platform/common/incoming_message_dispatcher.h" #include "flutter/shell/platform/common/path_utils.h" @@ -391,6 +392,9 @@ static void SendPointerEventWithData(GLFWwindow* window, event.y *= pixels_per_coordinate; event.scroll_delta_x *= pixels_per_coordinate; event.scroll_delta_y *= pixels_per_coordinate; + // TODO(loicsharma): This assumes all pointer events are on the implicit + // view and should be updated to support multiple views. + event.view_id = flutter::kFlutterImplicitViewId; FlutterEngineSendPointerEvent(controller->engine->flutter_engine, &event, 1); diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 507d9e2271470..cc33e6b7e8217 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -10,6 +10,7 @@ #include #include +#include "flutter/common/constants.h" #include "flutter/shell/platform/common/app_lifecycle_state.h" #include "flutter/shell/platform/common/engine_switches.h" #include "flutter/shell/platform/embedder/embedder.h" @@ -832,6 +833,9 @@ void fl_engine_send_pointer_pan_zoom_event(FlEngine* self, fl_event.rotation = rotation; fl_event.device = kPointerPanZoomDeviceId; fl_event.device_kind = kFlutterPointerDeviceKindTrackpad; + // TODO(loicsharma): This assumes all pointer events are on the implicit + // view and should be updated to support multiple views. + fl_event.view_id = flutter::kFlutterImplicitViewId; self->embedder_api.SendPointerEvent(self->engine, &fl_event, 1); } diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index d668d2f447b6c..01dcbbefbee80 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -411,6 +411,9 @@ void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) { event.x = state->pan_zoom_start_x; event.y = state->pan_zoom_start_y; event.phase = FlutterPointerPhase::kPanZoomEnd; + // TODO(loicsharma): This assumes all pointer events are on the implicit + // view and should be updated to support multiple views. + event.view_id = 0; SendPointerEventWithData(event, state); } @@ -490,6 +493,10 @@ void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id, void FlutterWindowsView::SendPointerEventWithData( const FlutterPointerEvent& event_data, PointerState* state) { + // TODO(dkwingsmt): The Windows embedder doesn't support multi-view for now. + // Use the real view ID when it does. + int64_t view_id = kImplicitViewId; + // If sending anything other than an add, and the pointer isn't already added, // synthesize an add to satisfy Flutter's expectations about events. if (!state->flutter_state_is_added && @@ -499,6 +506,7 @@ void FlutterWindowsView::SendPointerEventWithData( event.x = event_data.x; event.y = event_data.y; event.buttons = 0; + event.view_id = view_id; SendPointerEventWithData(event, state); } @@ -513,6 +521,7 @@ void FlutterWindowsView::SendPointerEventWithData( event.device_kind = state->device_kind; event.device = state->pointer_id; event.buttons = state->buttons; + event.view_id = view_id_; // Set metadata that's always the same regardless of the event. event.struct_size = sizeof(event); From 14b430809588f0827ac8c4db41487f42c07c1c3e Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 22 Sep 2023 16:07:25 -0700 Subject: [PATCH 02/23] Add constants --- shell/platform/windows/flutter_windows_view.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 01dcbbefbee80..8186b0ac27a8b 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -6,6 +6,7 @@ #include +#include "flutter/common/constants.h" #include "flutter/fml/platform/win/wstring_conversion.h" #include "flutter/shell/platform/common/accessibility_bridge.h" #include "flutter/shell/platform/windows/keyboard_key_channel_handler.h" @@ -495,7 +496,7 @@ void FlutterWindowsView::SendPointerEventWithData( PointerState* state) { // TODO(dkwingsmt): The Windows embedder doesn't support multi-view for now. // Use the real view ID when it does. - int64_t view_id = kImplicitViewId; + int64_t view_id = flutter::kFlutterImplicitViewId; // If sending anything other than an add, and the pointer isn't already added, // synthesize an add to satisfy Flutter's expectations about events. From e9e363b6dd7dbe0611dc458639f0407473f18807 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 22 Sep 2023 16:15:51 -0700 Subject: [PATCH 03/23] fix compile --- shell/platform/windows/flutter_windows_view.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 8186b0ac27a8b..1d4f34154d6cd 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -522,7 +522,7 @@ void FlutterWindowsView::SendPointerEventWithData( event.device_kind = state->device_kind; event.device = state->pointer_id; event.buttons = state->buttons; - event.view_id = view_id_; + event.view_id = view_id; // Set metadata that's always the same regardless of the event. event.struct_size = sizeof(event); From cf6baa985d3b7a5c4660169bc835032ac213961f Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 6 Nov 2023 10:34:03 -0800 Subject: [PATCH 04/23] Fix event not sending view id --- shell/platform/embedder/embedder.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index eb6b4edb85bbf..dac00398087f1 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2334,6 +2334,7 @@ FlutterEngineResult FlutterEngineSendPointerEvent( pointer_data.pan_delta_y = 0.0; pointer_data.scale = SAFE_ACCESS(current, scale, 0.0); pointer_data.rotation = SAFE_ACCESS(current, rotation, 0.0); + pointer_data.view_id = SAFE_ACCESS(current, view_id, 0); packet->SetPointerData(i, pointer_data); current = reinterpret_cast( reinterpret_cast(current) + current->struct_size); From 5458a05ec86421220e3f21a7d28aff93e413cd39 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 8 Nov 2023 23:59:22 -0800 Subject: [PATCH 05/23] Fix doc --- examples/glfw/FlutterEmbedderGLFW.cc | 4 ++++ examples/glfw_drm/FlutterEmbedderGLFW.cc | 6 +++--- lib/ui/platform_dispatcher.dart | 9 ++------- lib/ui/window/pointer_data.cc | 7 +++++++ lib/ui/window/pointer_data.h | 9 +++++---- .../flutter/embedding/android/AndroidTouchProcessor.java | 4 +++- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/examples/glfw/FlutterEmbedderGLFW.cc b/examples/glfw/FlutterEmbedderGLFW.cc index 8b17b25958fc1..7ef145ec05649 100644 --- a/examples/glfw/FlutterEmbedderGLFW.cc +++ b/examples/glfw/FlutterEmbedderGLFW.cc @@ -13,6 +13,7 @@ static double g_pixelRatio = 1.0; static const size_t kInitialWindowWidth = 800; static const size_t kInitialWindowHeight = 600; +static constexpr int64_t kImplicitViewId = 0; static_assert(FLUTTER_ENGINE_VERSION == 1, "This Flutter Embedder was authored against the stable Flutter " @@ -33,6 +34,9 @@ void GLFWcursorPositionCallbackAtPhase(GLFWwindow* window, std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); + // TODO(loicsharma): This assumes all pointer events are on the implicit view + // and should be updated to the real view ID once GLFW support multiple views. + event.view_id = kImplicitViewId; FlutterEngineSendPointerEvent( reinterpret_cast(glfwGetWindowUserPointer(window)), &event, 1); diff --git a/examples/glfw_drm/FlutterEmbedderGLFW.cc b/examples/glfw_drm/FlutterEmbedderGLFW.cc index b759f83633882..03f81531b5933 100644 --- a/examples/glfw_drm/FlutterEmbedderGLFW.cc +++ b/examples/glfw_drm/FlutterEmbedderGLFW.cc @@ -57,9 +57,9 @@ void GLFWcursorPositionCallbackAtPhase(GLFWwindow* window, std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); - // TODO(loicsharma): This assumes all pointer events are on the implicit - // view and should be updated to support multiple views. - event.view_id = 0; + // TODO(loicsharma): This assumes all pointer events are on the implicit view + // and should be updated to the real view ID once GLFW support multiple views. + event.view_id = kImplicitViewId; FlutterEngineSendPointerEvent( reinterpret_cast(glfwGetWindowUserPointer(window)), &event, 1); diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 30194c9a89836..88b15bed1d54b 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -414,12 +414,7 @@ class PlatformDispatcher { } } - // If this value changes, update the encoding code in the following files: - // - // * pointer_data.h - // * pointer_data.cc - // * pointer.dart - // * AndroidTouchProcessor.java + // This value must match kPointerDataFieldCount in pointer_data.cc. static const int _kPointerDataFieldCount = 36; static PointerDataPacket _unpackPointerDataPacket(ByteData packet) { @@ -431,7 +426,7 @@ class PlatformDispatcher { for (int i = 0; i < length; ++i) { int offset = i * _kPointerDataFieldCount; data.add(PointerData( - // TODO(goderbauer): Wire up viewId. + // The unpacking code must match the struct in pointer_data.h. embedderId: packet.getInt64(kStride * offset++, _kFakeHostEndian), timeStamp: Duration(microseconds: packet.getInt64(kStride * offset++, _kFakeHostEndian)), change: PointerChange.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], diff --git a/lib/ui/window/pointer_data.cc b/lib/ui/window/pointer_data.cc index d628ca7015fca..704fa3a277223 100644 --- a/lib/ui/window/pointer_data.cc +++ b/lib/ui/window/pointer_data.cc @@ -8,6 +8,13 @@ namespace flutter { +// If kPointerDataFieldCount changes, update the corresponding values in: +// +// * platform_dispatcher.dart +// * AndroidTouchProcessor.java +static constexpr int kPointerDataFieldCount = 36; +static constexpr int kBytesPerField = sizeof(int64_t); + static_assert(sizeof(PointerData) == kBytesPerField * kPointerDataFieldCount, "PointerData has the wrong size"); diff --git a/lib/ui/window/pointer_data.h b/lib/ui/window/pointer_data.h index f0693baed6c5b..d817a876ab581 100644 --- a/lib/ui/window/pointer_data.h +++ b/lib/ui/window/pointer_data.h @@ -9,10 +9,6 @@ namespace flutter { -// If this value changes, update the pointer data unpacking code in -// platform_dispatcher.dart. -static constexpr int kPointerDataFieldCount = 36; -static constexpr int kBytesPerField = sizeof(int64_t); // Must match the button constants in events.dart. enum PointerButtonMouse : int64_t { kPointerButtonMousePrimary = 1 << 0, @@ -102,6 +98,11 @@ struct alignas(8) PointerData { double rotation; int64_t view_id; + // If this struct changes, update: + // + // * the unpacking code in platform_dispatcher.dart + // * the packing code in AndroidTouchProcessor.java + void Clear(); }; diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index 79f5de8ba7a4d..1b30669e952a4 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -80,7 +80,7 @@ public class AndroidTouchProcessor { int UNKNOWN = 4; } - // Must match the unpacking code in platform_dispatcher.dart. + // This value must match kPointerDataFieldCount in pointer_data.cc. private static final int POINTER_DATA_FIELD_COUNT = 36; @VisibleForTesting static final int BYTES_PER_FIELD = 8; @@ -134,6 +134,8 @@ public boolean onTouchEvent(@NonNull MotionEvent event) { public boolean onTouchEvent(@NonNull MotionEvent event, @NonNull Matrix transformMatrix) { int pointerCount = event.getPointerCount(); + // The following packing code must match the struct in pointer_data.h. + // Prepare a data packet of the appropriate size and order. ByteBuffer packet = ByteBuffer.allocateDirect(pointerCount * POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD); From 7464bb963e9145b12747ff35c33f09a6347754b6 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 9 Nov 2023 13:38:20 -0800 Subject: [PATCH 06/23] Doc and comment --- examples/glfw/FlutterEmbedderGLFW.cc | 4 ++-- examples/glfw_drm/FlutterEmbedderGLFW.cc | 4 ++-- lib/ui/window/pointer_data_packet_converter.cc | 6 +----- .../embedding/android/AndroidTouchProcessor.java | 11 +++++++---- shell/platform/glfw/flutter_glfw.cc | 4 ++-- shell/platform/linux/fl_engine.cc | 5 +++-- shell/platform/windows/flutter_windows_view.cc | 13 ++++++++----- 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/examples/glfw/FlutterEmbedderGLFW.cc b/examples/glfw/FlutterEmbedderGLFW.cc index 7ef145ec05649..3edbd64bc0a5d 100644 --- a/examples/glfw/FlutterEmbedderGLFW.cc +++ b/examples/glfw/FlutterEmbedderGLFW.cc @@ -34,8 +34,8 @@ void GLFWcursorPositionCallbackAtPhase(GLFWwindow* window, std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); - // TODO(loicsharma): This assumes all pointer events are on the implicit view - // and should be updated to the real view ID once GLFW support multiple views. + // This example only supports a single window, therefore we assume the pointer + // event occurred in the only view, the implicit view. event.view_id = kImplicitViewId; FlutterEngineSendPointerEvent( reinterpret_cast(glfwGetWindowUserPointer(window)), &event, diff --git a/examples/glfw_drm/FlutterEmbedderGLFW.cc b/examples/glfw_drm/FlutterEmbedderGLFW.cc index 03f81531b5933..7953d53f82b5b 100644 --- a/examples/glfw_drm/FlutterEmbedderGLFW.cc +++ b/examples/glfw_drm/FlutterEmbedderGLFW.cc @@ -57,8 +57,8 @@ void GLFWcursorPositionCallbackAtPhase(GLFWwindow* window, std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); - // TODO(loicsharma): This assumes all pointer events are on the implicit view - // and should be updated to the real view ID once GLFW support multiple views. + // This example only supports a single window, therefore we assume the pointer + // event occurred in the only view, the implicit view. event.view_id = kImplicitViewId; FlutterEngineSendPointerEvent( reinterpret_cast(glfwGetWindowUserPointer(window)), &event, diff --git a/lib/ui/window/pointer_data_packet_converter.cc b/lib/ui/window/pointer_data_packet_converter.cc index b34bce30aa151..6750a7da22761 100644 --- a/lib/ui/window/pointer_data_packet_converter.cc +++ b/lib/ui/window/pointer_data_packet_converter.cc @@ -69,11 +69,7 @@ void PointerDataPacketConverter::ConvertPointerData( break; } case PointerData::Change::kAdd: { - // TODO(loicsharma): The macOS embedder does not share - // its mouse state across its view controllers, resulting - // in multiple pointer adds for the same pointer. - // See: https://github.com/flutter/flutter/issues/125931 - // FML_DCHECK(states_.find(pointer_data.device) == states_.end()); + FML_DCHECK(states_.find(pointer_data.device) == states_.end()); EnsurePointerState(pointer_data); converted_pointers.push_back(pointer_data); break; diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index 1b30669e952a4..62cf40f9b3999 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -79,7 +79,6 @@ public class AndroidTouchProcessor { int SCALE = 3; int UNKNOWN = 4; } - // This value must match kPointerDataFieldCount in pointer_data.cc. private static final int POINTER_DATA_FIELD_COUNT = 36; @VisibleForTesting static final int BYTES_PER_FIELD = 8; @@ -92,6 +91,8 @@ public class AndroidTouchProcessor { // This flag indicates whether the original Android pointer events were batched together. private static final int POINTER_DATA_FLAG_BATCHED = 1; + private static final int IMPLICIT_VIEW_ID = 0; + @NonNull private final FlutterRenderer renderer; @NonNull private final MotionEventTracker motionEventTracker; @@ -255,6 +256,10 @@ private void addPointerForIndex( if (pointerChange == -1) { return; } + // TODO(dkwingsmt): Use the correct source view ID once Android supports + // multiple views. + // https://github.com/flutter/flutter/issues/138167 + final int viewId = IMPLICIT_VIEW_ID; final int pointerId = event.getPointerId(pointerIndex); int pointerKind = getPointerDeviceTypeForToolType(event.getToolType(pointerIndex)); @@ -413,9 +418,7 @@ private void addPointerForIndex( packet.putDouble(0.0); // pan_delta_y packet.putDouble(1.0); // scale packet.putDouble(0.0); // rotation - // TODO(loicsharma): This assumes all pointer events are on the implicit - // view and should be updated to support multiple views. - packet.putLong(0); // view_id + packet.putLong(viewId); // view_id if (isTrackpadPan && (panZoomType == PointerChange.PAN_ZOOM_END)) { ongoingPans.remove(pointerId); diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index d3751555c77b2..266a97bec58cc 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -392,8 +392,8 @@ static void SendPointerEventWithData(GLFWwindow* window, event.y *= pixels_per_coordinate; event.scroll_delta_x *= pixels_per_coordinate; event.scroll_delta_y *= pixels_per_coordinate; - // TODO(loicsharma): This assumes all pointer events are on the implicit - // view and should be updated to support multiple views. + // The GLFW embedder doesn't support multiple views. We assume all pointer + // events come from the only view, the implicit view. event.view_id = flutter::kFlutterImplicitViewId; FlutterEngineSendPointerEvent(controller->engine->flutter_engine, &event, 1); diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index cc33e6b7e8217..7941222fbcf3c 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -833,8 +833,9 @@ void fl_engine_send_pointer_pan_zoom_event(FlEngine* self, fl_event.rotation = rotation; fl_event.device = kPointerPanZoomDeviceId; fl_event.device_kind = kFlutterPointerDeviceKindTrackpad; - // TODO(loicsharma): This assumes all pointer events are on the implicit - // view and should be updated to support multiple views. + // TODO(dkwingsmt): Assign the correct view ID once the Linux embedder + // supports multiple views. + // https://github.com/flutter/flutter/issues/138178 fl_event.view_id = flutter::kFlutterImplicitViewId; self->embedder_api.SendPointerEvent(self->engine, &fl_event, 1); } diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 5fe7ef586e3f1..d1001695cc65e 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -408,15 +408,17 @@ void FlutterWindowsView::SendPointerPanZoomUpdate(int32_t device_id, } void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) { + // TODO(dkwingsmt): Use the correct view ID once the Windows embedder supports + // multiple views. + // https://github.com/flutter/flutter/issues/138179 + int64_t view_id = flutter::kFlutterImplicitViewId; auto state = GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id); FlutterPointerEvent event = {}; event.x = state->pan_zoom_start_x; event.y = state->pan_zoom_start_y; event.phase = FlutterPointerPhase::kPanZoomEnd; - // TODO(loicsharma): This assumes all pointer events are on the implicit - // view and should be updated to support multiple views. - event.view_id = 0; + event.view_id = view_id; SendPointerEventWithData(event, state); } @@ -496,8 +498,9 @@ void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id, void FlutterWindowsView::SendPointerEventWithData( const FlutterPointerEvent& event_data, PointerState* state) { - // TODO(dkwingsmt): The Windows embedder doesn't support multi-view for now. - // Use the real view ID when it does. + // TODO(dkwingsmt): Use the correct view ID once the Windows embedder supports + // multiple views. + // https://github.com/flutter/flutter/issues/138179 int64_t view_id = flutter::kFlutterImplicitViewId; // If sending anything other than an add, and the pointer isn't already added, From 91edc9b708c221b17935c28577d0250e86ad1a3e Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 9 Nov 2023 13:43:45 -0800 Subject: [PATCH 07/23] More comment --- lib/ui/window/pointer_data.h | 11 ++++++----- .../window/pointer_data_packet_converter_unittests.cc | 4 +++- .../embedding/android/AndroidTouchProcessor.java | 2 ++ .../ios/framework/Source/FlutterViewController.mm | 7 ++++--- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/ui/window/pointer_data.h b/lib/ui/window/pointer_data.h index d817a876ab581..1fd139437b36c 100644 --- a/lib/ui/window/pointer_data.h +++ b/lib/ui/window/pointer_data.h @@ -29,6 +29,12 @@ enum PointerButtonStylus : int64_t { }; // This structure is unpacked by platform_dispatcher.dart. +// +// If this struct changes, update: +// +// * kPointerDataFieldCount in pointer_data.cc +// * the unpacking code in platform_dispatcher.dart +// * the packing code in AndroidTouchProcessor.java struct alignas(8) PointerData { // Must match the PointerChange enum in pointer.dart. enum class Change : int64_t { @@ -98,11 +104,6 @@ struct alignas(8) PointerData { double rotation; int64_t view_id; - // If this struct changes, update: - // - // * the unpacking code in platform_dispatcher.dart - // * the packing code in AndroidTouchProcessor.java - void Clear(); }; diff --git a/lib/ui/window/pointer_data_packet_converter_unittests.cc b/lib/ui/window/pointer_data_packet_converter_unittests.cc index 3d6dce7571d98..c652bc6749855 100644 --- a/lib/ui/window/pointer_data_packet_converter_unittests.cc +++ b/lib/ui/window/pointer_data_packet_converter_unittests.cc @@ -11,6 +11,8 @@ namespace flutter { namespace testing { +static constexpr int64_t kImplicitViewId = 0; + void CreateSimulatedPointerData(PointerData& data, // NOLINT PointerData::Change change, int64_t device, @@ -129,7 +131,7 @@ void CreateSimulatedTrackpadGestureData(PointerData& data, // NOLINT data.pan_delta_y = 0.0; data.scale = scale; data.rotation = rotation; - data.view_id = 0; + data.view_id = kImplicitViewId; } void UnpackPointerPacket(std::vector& output, // NOLINT diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index 62cf40f9b3999..d9ccf2ee2d103 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -79,6 +79,7 @@ public class AndroidTouchProcessor { int SCALE = 3; int UNKNOWN = 4; } + // This value must match kPointerDataFieldCount in pointer_data.cc. private static final int POINTER_DATA_FIELD_COUNT = 36; @VisibleForTesting static final int BYTES_PER_FIELD = 8; @@ -91,6 +92,7 @@ public class AndroidTouchProcessor { // This flag indicates whether the original Android pointer events were batched together. private static final int POINTER_DATA_FLAG_BATCHED = 1; + // The view ID for the only view in a single-view Flutter app. private static final int IMPLICIT_VIEW_ID = 0; @NonNull private final FlutterRenderer renderer; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 1870f936b4341..e4eb3786cc2ca 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -1176,9 +1176,10 @@ - (void)dispatchTouches:(NSSet*)touches pointer_data.device = reinterpret_cast(touch); - // TODO(loicsharma): This assumes all pointer events are on the implicit - // view and should be updated to support multiple views. - pointer_data.view_id = 0; + // TODO(dkwingsmt): Use the correct view ID once the iOS shell supports + // multiple views. + // https://github.com/flutter/flutter/issues/138168 + pointer_data.view_id = flutter::kFlutterImplicitViewId; // Pointer will be generated in pointer_data_packet_converter.cc. pointer_data.pointer_identifier = 0; From 307ec40f16ec1f3d6927ea59fdb5d379c1e25fd9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 9 Nov 2023 14:06:08 -0800 Subject: [PATCH 08/23] Add view ID for all pointer events in Win --- .../platform/windows/flutter_windows_view.cc | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index d1001695cc65e..df5e2763449be 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -20,6 +20,13 @@ namespace { // for a window resize operation to complete. constexpr std::chrono::milliseconds kWindowResizeTimeout{100}; +// TODO(dkwingsmt): Use the correct view ID for pointer events once the Windows +// embedder supports multiple views. +// https://github.com/flutter/flutter/issues/138179 +int64_t _viewIdForPointerEvent() { + return flutter::kFlutterImplicitViewId; +} + /// Returns true if the surface will be updated as part of the resize process. /// /// This is called on window resize to determine if the platform thread needs @@ -333,6 +340,7 @@ void FlutterWindowsView::SendPointerMove(double x, FlutterPointerEvent event = {}; event.x = x; event.y = y; + event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); @@ -344,6 +352,7 @@ void FlutterWindowsView::SendPointerDown(double x, FlutterPointerEvent event = {}; event.x = x; event.y = y; + event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); @@ -357,6 +366,7 @@ void FlutterWindowsView::SendPointerUp(double x, FlutterPointerEvent event = {}; event.x = x; event.y = y; + event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); @@ -372,6 +382,7 @@ void FlutterWindowsView::SendPointerLeave(double x, event.x = x; event.y = y; event.phase = FlutterPointerPhase::kRemove; + event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -386,6 +397,7 @@ void FlutterWindowsView::SendPointerPanZoomStart(int32_t device_id, event.x = x; event.y = y; event.phase = FlutterPointerPhase::kPanZoomStart; + event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -404,21 +416,18 @@ void FlutterWindowsView::SendPointerPanZoomUpdate(int32_t device_id, event.scale = scale; event.rotation = rotation; event.phase = FlutterPointerPhase::kPanZoomUpdate; + event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) { - // TODO(dkwingsmt): Use the correct view ID once the Windows embedder supports - // multiple views. - // https://github.com/flutter/flutter/issues/138179 - int64_t view_id = flutter::kFlutterImplicitViewId; auto state = GetOrCreatePointerState(kFlutterPointerDeviceKindTrackpad, device_id); FlutterPointerEvent event = {}; event.x = state->pan_zoom_start_x; event.y = state->pan_zoom_start_y; event.phase = FlutterPointerPhase::kPanZoomEnd; - event.view_id = view_id; + event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -476,6 +485,7 @@ void FlutterWindowsView::SendScroll(double x, event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll; event.scroll_delta_x = delta_x * scroll_offset_multiplier; event.scroll_delta_y = delta_y * scroll_offset_multiplier; + event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); } @@ -491,6 +501,7 @@ void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id, event.y = y; event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScrollInertiaCancel; + event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); } @@ -498,11 +509,6 @@ void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id, void FlutterWindowsView::SendPointerEventWithData( const FlutterPointerEvent& event_data, PointerState* state) { - // TODO(dkwingsmt): Use the correct view ID once the Windows embedder supports - // multiple views. - // https://github.com/flutter/flutter/issues/138179 - int64_t view_id = flutter::kFlutterImplicitViewId; - // If sending anything other than an add, and the pointer isn't already added, // synthesize an add to satisfy Flutter's expectations about events. if (!state->flutter_state_is_added && @@ -512,7 +518,7 @@ void FlutterWindowsView::SendPointerEventWithData( event.x = event_data.x; event.y = event_data.y; event.buttons = 0; - event.view_id = view_id; + event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -527,7 +533,7 @@ void FlutterWindowsView::SendPointerEventWithData( event.device_kind = state->device_kind; event.device = state->pointer_id; event.buttons = state->buttons; - event.view_id = view_id; + event.view_id = _viewIdForPointerEvent(); // Set metadata that's always the same regardless of the event. event.struct_size = sizeof(event); From 7603a36998f965f45e58ef4f09d8c8c7fb22d022 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 9 Nov 2023 14:12:39 -0800 Subject: [PATCH 09/23] Better TODO for iOS --- .../framework/Source/FlutterViewController.mm | 19 +++++++++++++++---- shell/platform/linux/fl_engine.cc | 4 ++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index e4eb3786cc2ca..c1f65bc10c000 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -54,6 +54,13 @@ CGPoint last_translation = CGPointZero; } MouseState; +// TODO(dkwingsmt): Use the correct view ID for pointer events once the iOS +// shell supports multiple views. +// https://github.com/flutter/flutter/issues/138168 +int64_t _viewIdForPointerEvent() { + return flutter::kFlutterImplicitViewId; +} + // This is left a FlutterBinaryMessenger privately for now to give people a chance to notice the // change. Unfortunately unless you have Werror turned on, incompatible pointers as arguments are // just a warning. @@ -928,6 +935,7 @@ - (void)flushOngoingTouches { pointer_data.change = flutter::PointerData::Change::kCancel; pointer_data.device = device.longLongValue; pointer_data.pointer_identifier = 0; + pointer_data.view_id = _viewIdForPointerEvent(); // Anything we put here will be arbitrary since there are no touches. pointer_data.physical_x = 0; @@ -1176,10 +1184,7 @@ - (void)dispatchTouches:(NSSet*)touches pointer_data.device = reinterpret_cast(touch); - // TODO(dkwingsmt): Use the correct view ID once the iOS shell supports - // multiple views. - // https://github.com/flutter/flutter/issues/138168 - pointer_data.view_id = flutter::kFlutterImplicitViewId; + pointer_data.view_id = _viewIdForPointerEvent(); // Pointer will be generated in pointer_data_packet_converter.cc. pointer_data.pointer_identifier = 0; @@ -2398,6 +2403,7 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer pointer_data.device = reinterpret_cast(_continuousScrollingPanGestureRecognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; pointer_data.signal_kind = flutter::PointerData::SignalKind::kScrollInertiaCancel; + pointer_data.view_id = _viewIdForPointerEvent(); if (event.timestamp < _scrollInertiaEventAppKitDeadline) { // Only send the event if it occured before the expected natural end of gesture momentum. @@ -2421,6 +2427,7 @@ - (void)hoverEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4)) flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kMouse; + pointer_data.view_id = _viewIdForPointerEvent(); switch (_hoverGestureRecognizer.state) { case UIGestureRecognizerStateBegan: @@ -2459,6 +2466,7 @@ - (void)hoverEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4)) inertia_cancel.device = reinterpret_cast(_continuousScrollingPanGestureRecognizer); inertia_cancel.kind = flutter::PointerData::DeviceKind::kTrackpad; inertia_cancel.signal_kind = flutter::PointerData::SignalKind::kScrollInertiaCancel; + inertia_cancel.view_id = _viewIdForPointerEvent(); packet->SetPointerData(/*i=*/1, inertia_cancel); [_engine.get() dispatchPointerDataPacket:std::move(packet)]; _scrollInertiaEventStartline = DBL_MAX; @@ -2482,6 +2490,7 @@ - (void)discreteScrollEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(io pointer_data.signal_kind = flutter::PointerData::SignalKind::kScroll; pointer_data.scroll_delta_x = (translation.x - _mouseState.last_translation.x); pointer_data.scroll_delta_y = -(translation.y - _mouseState.last_translation.y); + pointer_data.view_id = _viewIdForPointerEvent(); // The translation reported by UIPanGestureRecognizer is the total translation // generated by the pan gesture since the gesture began. We need to be able @@ -2505,6 +2514,7 @@ - (void)continuousScrollEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE( flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; + pointer_data.view_id = _viewIdForPointerEvent(); switch (recognizer.state) { case UIGestureRecognizerStateBegan: pointer_data.change = flutter::PointerData::Change::kPanZoomStart; @@ -2553,6 +2563,7 @@ - (void)pinchEvent:(UIPinchGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4) flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; + pointer_data.view_id = _viewIdForPointerEvent(); switch (recognizer.state) { case UIGestureRecognizerStateBegan: pointer_data.change = flutter::PointerData::Change::kPanZoomStart; diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 7941222fbcf3c..ee4cd06004636 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -803,6 +803,10 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, fl_event.device_kind = kFlutterPointerDeviceKindMouse; fl_event.buttons = buttons; fl_event.device = kMousePointerDeviceId; + // TODO(dkwingsmt): Assign the correct view ID once the Linux embedder + // supports multiple views. + // https://github.com/flutter/flutter/issues/138178 + fl_event.view_id = flutter::kFlutterImplicitViewId; self->embedder_api.SendPointerEvent(self->engine, &fl_event, 1); } From fe1cc5274416a64faca5b6f644672faf4ec6c213 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 9 Nov 2023 14:30:23 -0800 Subject: [PATCH 10/23] Compile --- .../darwin/ios/framework/Source/FlutterViewController.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index c1f65bc10c000..66423fe97c9bf 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -9,6 +9,7 @@ #import #include +#include "flutter/common/constants.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/platform/darwin/platform_version.h" From 9f70c4c385e93cb9f841a94a8b25e10d2641cb75 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 11 Dec 2023 13:51:51 -0800 Subject: [PATCH 11/23] Address comments --- ...pointer_data_packet_converter_unittests.cc | 4 +--- .../android/AndroidTouchProcessor.java | 2 +- shell/platform/embedder/embedder.h | 11 +++++++++- .../platform/windows/flutter_windows_view.cc | 22 ++++--------------- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/lib/ui/window/pointer_data_packet_converter_unittests.cc b/lib/ui/window/pointer_data_packet_converter_unittests.cc index c652bc6749855..3d6dce7571d98 100644 --- a/lib/ui/window/pointer_data_packet_converter_unittests.cc +++ b/lib/ui/window/pointer_data_packet_converter_unittests.cc @@ -11,8 +11,6 @@ namespace flutter { namespace testing { -static constexpr int64_t kImplicitViewId = 0; - void CreateSimulatedPointerData(PointerData& data, // NOLINT PointerData::Change change, int64_t device, @@ -131,7 +129,7 @@ void CreateSimulatedTrackpadGestureData(PointerData& data, // NOLINT data.pan_delta_y = 0.0; data.scale = scale; data.rotation = rotation; - data.view_id = kImplicitViewId; + data.view_id = 0; } void UnpackPointerPacket(std::vector& output, // NOLINT diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index d9ccf2ee2d103..0c727c4d8fb5a 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -260,7 +260,7 @@ private void addPointerForIndex( } // TODO(dkwingsmt): Use the correct source view ID once Android supports // multiple views. - // https://github.com/flutter/flutter/issues/138167 + // https://github.com/flutter/flutter/issues/134405 final int viewId = IMPLICIT_VIEW_ID; final int pointerId = event.getPointerId(pointerIndex); diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 4ccfd6957c5ba..1b7f4f6707de1 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -266,6 +266,15 @@ typedef enum { typedef struct _FlutterEngine* FLUTTER_API_SYMBOL(FlutterEngine); +/// Identifier for views. +/// +/// The responsibility for generating view IDs lies with the embedding. The +/// engine does not assume any specifics about the generation algorithm, +/// including whether it utilizes the entire range of int64_t or permits the +/// use of zero or negative IDs. The only requirement is that at any given +/// moment, no two views share the same ID. +typedef int64_t FlutterViewId; + typedef struct { /// horizontal scale factor double scaleX; @@ -962,7 +971,7 @@ typedef struct { /// The rotation of the pan/zoom in radians, where 0.0 is the initial angle. double rotation; /// The identifier of the view that received the pointer event. - int64_t view_id; + FlutterViewId view_id; } FlutterPointerEvent; typedef enum { diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index df935a125574e..0f1aa9b81f400 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -20,13 +20,6 @@ namespace { // for a window resize operation to complete. constexpr std::chrono::milliseconds kWindowResizeTimeout{100}; -// TODO(dkwingsmt): Use the correct view ID for pointer events once the Windows -// embedder supports multiple views. -// https://github.com/flutter/flutter/issues/138179 -int64_t _viewIdForPointerEvent() { - return flutter::kFlutterImplicitViewId; -} - /// Returns true if the surface will be updated as part of the resize process. /// /// This is called on window resize to determine if the platform thread needs @@ -372,7 +365,6 @@ void FlutterWindowsView::SendPointerMove(double x, FlutterPointerEvent event = {}; event.x = x; event.y = y; - event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); @@ -384,7 +376,6 @@ void FlutterWindowsView::SendPointerDown(double x, FlutterPointerEvent event = {}; event.x = x; event.y = y; - event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); @@ -398,7 +389,6 @@ void FlutterWindowsView::SendPointerUp(double x, FlutterPointerEvent event = {}; event.x = x; event.y = y; - event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); @@ -414,7 +404,6 @@ void FlutterWindowsView::SendPointerLeave(double x, event.x = x; event.y = y; event.phase = FlutterPointerPhase::kRemove; - event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -429,7 +418,6 @@ void FlutterWindowsView::SendPointerPanZoomStart(int32_t device_id, event.x = x; event.y = y; event.phase = FlutterPointerPhase::kPanZoomStart; - event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -448,7 +436,6 @@ void FlutterWindowsView::SendPointerPanZoomUpdate(int32_t device_id, event.scale = scale; event.rotation = rotation; event.phase = FlutterPointerPhase::kPanZoomUpdate; - event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -459,7 +446,6 @@ void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) { event.x = state->pan_zoom_start_x; event.y = state->pan_zoom_start_y; event.phase = FlutterPointerPhase::kPanZoomEnd; - event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -517,7 +503,6 @@ void FlutterWindowsView::SendScroll(double x, event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll; event.scroll_delta_x = delta_x * scroll_offset_multiplier; event.scroll_delta_y = delta_y * scroll_offset_multiplier; - event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); } @@ -533,7 +518,6 @@ void FlutterWindowsView::SendScrollInertiaCancel(int32_t device_id, event.y = y; event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScrollInertiaCancel; - event.view_id = _viewIdForPointerEvent(); SetEventPhaseFromCursorButtonState(&event, state); SendPointerEventWithData(event, state); } @@ -550,7 +534,6 @@ void FlutterWindowsView::SendPointerEventWithData( event.x = event_data.x; event.y = event_data.y; event.buttons = 0; - event.view_id = _viewIdForPointerEvent(); SendPointerEventWithData(event, state); } @@ -565,7 +548,10 @@ void FlutterWindowsView::SendPointerEventWithData( event.device_kind = state->device_kind; event.device = state->pointer_id; event.buttons = state->buttons; - event.view_id = _viewIdForPointerEvent(); + // TODO(dkwingsmt): Use the correct view ID for pointer events once the + // Windows embedder supports multiple views. + // https://github.com/flutter/flutter/issues/138179 + event.view_id = flutter::kFlutterImplicitViewId; // Set metadata that's always the same regardless of the event. event.struct_size = sizeof(event); From f1da532a740f513ab4dc12a37a85f49cd0a49e2c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 11 Dec 2023 14:44:54 -0800 Subject: [PATCH 12/23] Some FlutterViewId --- examples/glfw/FlutterEmbedderGLFW.cc | 2 +- examples/glfw_drm/FlutterEmbedderGLFW.cc | 2 +- lib/ui/pointer.dart | 2 +- .../ios/framework/Source/FlutterViewController.mm | 7 ------- .../macos/framework/Source/FlutterViewController.mm | 4 ++-- shell/platform/embedder/embedder.cc | 2 +- shell/platform/embedder/embedder.h | 10 +++++----- 7 files changed, 11 insertions(+), 18 deletions(-) diff --git a/examples/glfw/FlutterEmbedderGLFW.cc b/examples/glfw/FlutterEmbedderGLFW.cc index 3edbd64bc0a5d..ae7fad5dec2ba 100644 --- a/examples/glfw/FlutterEmbedderGLFW.cc +++ b/examples/glfw/FlutterEmbedderGLFW.cc @@ -13,7 +13,7 @@ static double g_pixelRatio = 1.0; static const size_t kInitialWindowWidth = 800; static const size_t kInitialWindowHeight = 600; -static constexpr int64_t kImplicitViewId = 0; +static constexpr FlutterViewId kImplicitViewId = 0; static_assert(FLUTTER_ENGINE_VERSION == 1, "This Flutter Embedder was authored against the stable Flutter " diff --git a/examples/glfw_drm/FlutterEmbedderGLFW.cc b/examples/glfw_drm/FlutterEmbedderGLFW.cc index 7953d53f82b5b..f4a9ce8ead473 100644 --- a/examples/glfw_drm/FlutterEmbedderGLFW.cc +++ b/examples/glfw_drm/FlutterEmbedderGLFW.cc @@ -26,7 +26,7 @@ static const size_t kInitialWindowHeight = 600; // Maximum damage history - for triple buffering we need to store damage for // last two frames; Some Android devices (Pixel 4) use quad buffering. static const int kMaxHistorySize = 10; -static constexpr int64_t kImplicitViewId = 0; +static constexpr FlutterViewId kImplicitViewId = 0; // Keeps track of the most recent frame damages so that existing damage can // be easily computed. diff --git a/lib/ui/pointer.dart b/lib/ui/pointer.dart index 82c7e11f81096..cff2ec7fdf244 100644 --- a/lib/ui/pointer.dart +++ b/lib/ui/pointer.dart @@ -420,7 +420,7 @@ class PointerData { 'panDeltaY: $panDeltaY, ' 'scale: $scale, ' 'rotation: $rotation, ' - 'viewId: $viewId ' + 'viewId: $viewId' ')'; } } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 07dd336d82af2..4c77e8dbf8a0e 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -55,13 +55,6 @@ CGPoint last_translation = CGPointZero; } MouseState; -// TODO(dkwingsmt): Use the correct view ID for pointer events once the iOS -// shell supports multiple views. -// https://github.com/flutter/flutter/issues/138168 -int64_t _viewIdForPointerEvent() { - return flutter::kFlutterImplicitViewId; -} - // This is left a FlutterBinaryMessenger privately for now to give people a chance to notice the // change. Unfortunately unless you have Werror turned on, incompatible pointers as arguments are // just a warning. diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 74ca6d73755e4..6f61cf9578497 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -743,7 +743,7 @@ - (void)dispatchMouseEvent:(NSEvent*)event phase:(FlutterPointerPhase)phase { .device_kind = deviceKind, // If a click triggered a synthesized kAdd, don't pass the buttons in that event. .buttons = phase == kAdd ? 0 : _mouseState.buttons, - .view_id = static_cast(_viewId), + .view_id = static_cast(_viewId), }; if (phase == kPanZoomUpdate) { @@ -1050,7 +1050,7 @@ - (void)touchesBeganWithEvent:(NSEvent*)event { .device = kPointerPanZoomDeviceId, .signal_kind = kFlutterPointerSignalKindScrollInertiaCancel, .device_kind = kFlutterPointerDeviceKindTrackpad, - .view_id = static_cast(_viewId), + .view_id = static_cast(_viewId), }; [_engine sendPointerEvent:flutterEvent]; diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index f87ef3d66c007..c4191dcf5226f 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -102,7 +102,7 @@ extern const intptr_t kPlatformStrongDillSize; const int32_t kFlutterSemanticsNodeIdBatchEnd = -1; const int32_t kFlutterSemanticsCustomActionIdBatchEnd = -1; -static constexpr int64_t kFlutterImplicitViewId = 0; +static constexpr FlutterViewId kFlutterImplicitViewId = 0; // A message channel to send platform-independent FlutterKeyData to the // framework. diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 1b7f4f6707de1..47bd83d1f7d16 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -268,11 +268,11 @@ typedef struct _FlutterEngine* FLUTTER_API_SYMBOL(FlutterEngine); /// Identifier for views. /// -/// The responsibility for generating view IDs lies with the embedding. The -/// engine does not assume any specifics about the generation algorithm, -/// including whether it utilizes the entire range of int64_t or permits the -/// use of zero or negative IDs. The only requirement is that at any given -/// moment, no two views share the same ID. +/// How view IDs are generated is decided by the embedding. The engine does not +/// assume any specifics about the generation algorithm, including whether it +/// utilizes the entire range of int64_t or permits the use of zero or negative +/// IDs. The only requirement is that at any given moment, no two views share +/// the same ID. typedef int64_t FlutterViewId; typedef struct { From 5256e41d5a71014b1d372c15761a55088b6c0b74 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 11 Dec 2023 14:56:33 -0800 Subject: [PATCH 13/23] Embedder test --- shell/platform/embedder/fixtures/main.dart | 15 ++++++- .../embedder/tests/embedder_unittests.cc | 42 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index 7687dca71437f..ada2f43ca5542 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -1303,7 +1303,7 @@ void pointer_data_packet() { (PointerDataPacket packet) { signalNativeCount(packet.data.length); - for (final pointerData in packet.data) { + for (final PointerData pointerData in packet.data) { signalNativeMessage(pointerData.toString()); } }; @@ -1311,6 +1311,19 @@ void pointer_data_packet() { signalNativeTest(); } +@pragma('vm:entry-point') +void pointer_data_packet_view_id() { + PlatformDispatcher.instance.onPointerDataPacket = (PointerDataPacket packet) { + assert(packet.data.length == 1); + + for (final PointerData pointerData in packet.data) { + signalNativeMessage('ViewID: ${pointerData.viewId}'); + } + }; + + signalNativeTest(); +} + @pragma('vm:entry-point') Future channel_listener_response() async { channelBuffers.setListener('test/listen', diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index 9e6fa5f6e5351..a9e0e72a919f0 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -2666,6 +2666,48 @@ TEST_F(EmbedderTest, CanSendPointer) { message_latch.Wait(); } +/// Send a pointer event to Dart and wait until the Dart code echos with the +/// view ID. +TEST_F(EmbedderTest, CanSendPointerWithViewId) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext); + EmbedderConfigBuilder builder(context); + builder.SetSoftwareRendererConfig(); + builder.SetDartEntrypoint("pointer_data_packet_view_id"); + + fml::AutoResetWaitableEvent ready_latch, count_latch, message_latch; + context.AddNativeCallback( + "SignalNativeTest", + CREATE_NATIVE_ENTRY( + [&ready_latch](Dart_NativeArguments args) { ready_latch.Signal(); })); + context.AddNativeCallback( + "SignalNativeMessage", + CREATE_NATIVE_ENTRY([&message_latch](Dart_NativeArguments args) { + auto message = tonic::DartConverter::FromDart( + Dart_GetNativeArgument(args, 0)); + ASSERT_EQ("ViewID: 2", message); + message_latch.Signal(); + })); + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + ready_latch.Wait(); + + FlutterPointerEvent pointer_event = {}; + pointer_event.struct_size = sizeof(FlutterPointerEvent); + pointer_event.phase = FlutterPointerPhase::kAdd; + pointer_event.x = 123; + pointer_event.y = 456; + pointer_event.timestamp = static_cast(1234567890); + pointer_event.view_id = 2; + + FlutterEngineResult result = + FlutterEngineSendPointerEvent(engine.get(), &pointer_event, 1); + ASSERT_EQ(result, kSuccess); + + message_latch.Wait(); +} + TEST_F(EmbedderTest, RegisterChannelListener) { auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext); From 8d20227946142f2f7626443660a8d8336ecdb324 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 11 Dec 2023 15:02:51 -0800 Subject: [PATCH 14/23] Fix ios compile --- .../framework/Source/FlutterViewController.mm | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 4c77e8dbf8a0e..5fe96acd2f86c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -59,6 +59,11 @@ // change. Unfortunately unless you have Werror turned on, incompatible pointers as arguments are // just a warning. @interface FlutterViewController () +// TODO(dkwingsmt): Make the view ID property public once the iOS shell +// supports multiple views. +// https://github.com/flutter/flutter/issues/138168 +@property(nonatomic, assign) int64_t viewId; + @property(nonatomic, readwrite, getter=isDisplayingFlutterUI) BOOL displayingFlutterUI; @property(nonatomic, assign) BOOL isHomeIndicatorHidden; @property(nonatomic, assign) BOOL isPresentingViewControllerAnimating; @@ -214,6 +219,12 @@ - (instancetype)initWithCoder:(NSCoder*)aDecoder { return self; } +- (int64_t)viewId { + // TODO(dkwingsmt): Fill the view ID property with the correct value once the + // iOS shell supports multiple views. + return flutter::kFlutterImplicitViewId; +} + - (void)awakeFromNib { [super awakeFromNib]; if (!_engine) { @@ -929,7 +940,7 @@ - (void)flushOngoingTouches { pointer_data.change = flutter::PointerData::Change::kCancel; pointer_data.device = device.longLongValue; pointer_data.pointer_identifier = 0; - pointer_data.view_id = _viewIdForPointerEvent(); + pointer_data.view_id = self.viewId; // Anything we put here will be arbitrary since there are no touches. pointer_data.physical_x = 0; @@ -1178,7 +1189,7 @@ - (void)dispatchTouches:(NSSet*)touches pointer_data.device = reinterpret_cast(touch); - pointer_data.view_id = _viewIdForPointerEvent(); + pointer_data.view_id = self.viewId; // Pointer will be generated in pointer_data_packet_converter.cc. pointer_data.pointer_identifier = 0; @@ -2397,7 +2408,7 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer pointer_data.device = reinterpret_cast(_continuousScrollingPanGestureRecognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; pointer_data.signal_kind = flutter::PointerData::SignalKind::kScrollInertiaCancel; - pointer_data.view_id = _viewIdForPointerEvent(); + pointer_data.view_id = self.viewId; if (event.timestamp < _scrollInertiaEventAppKitDeadline) { // Only send the event if it occured before the expected natural end of gesture momentum. @@ -2421,7 +2432,7 @@ - (void)hoverEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4)) flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kMouse; - pointer_data.view_id = _viewIdForPointerEvent(); + pointer_data.view_id = self.viewId; switch (_hoverGestureRecognizer.state) { case UIGestureRecognizerStateBegan: @@ -2460,7 +2471,7 @@ - (void)hoverEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4)) inertia_cancel.device = reinterpret_cast(_continuousScrollingPanGestureRecognizer); inertia_cancel.kind = flutter::PointerData::DeviceKind::kTrackpad; inertia_cancel.signal_kind = flutter::PointerData::SignalKind::kScrollInertiaCancel; - inertia_cancel.view_id = _viewIdForPointerEvent(); + inertia_cancel.view_id = self.viewId; packet->SetPointerData(/*i=*/1, inertia_cancel); [_engine.get() dispatchPointerDataPacket:std::move(packet)]; _scrollInertiaEventStartline = DBL_MAX; @@ -2484,7 +2495,7 @@ - (void)discreteScrollEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(io pointer_data.signal_kind = flutter::PointerData::SignalKind::kScroll; pointer_data.scroll_delta_x = (translation.x - _mouseState.last_translation.x); pointer_data.scroll_delta_y = -(translation.y - _mouseState.last_translation.y); - pointer_data.view_id = _viewIdForPointerEvent(); + pointer_data.view_id = self.viewId; // The translation reported by UIPanGestureRecognizer is the total translation // generated by the pan gesture since the gesture began. We need to be able @@ -2508,7 +2519,7 @@ - (void)continuousScrollEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE( flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; - pointer_data.view_id = _viewIdForPointerEvent(); + pointer_data.view_id = self.viewId; switch (recognizer.state) { case UIGestureRecognizerStateBegan: pointer_data.change = flutter::PointerData::Change::kPanZoomStart; @@ -2557,7 +2568,7 @@ - (void)pinchEvent:(UIPinchGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4) flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; - pointer_data.view_id = _viewIdForPointerEvent(); + pointer_data.view_id = self.viewId; switch (recognizer.state) { case UIGestureRecognizerStateBegan: pointer_data.change = flutter::PointerData::Change::kPanZoomStart; From 3954a346691b87221339cdc5e82737dd6b16fb65 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 11 Dec 2023 15:08:52 -0800 Subject: [PATCH 15/23] reorder --- .../ios/framework/Source/FlutterViewController.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 5fe96acd2f86c..97ee05d8f29a3 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -219,12 +219,6 @@ - (instancetype)initWithCoder:(NSCoder*)aDecoder { return self; } -- (int64_t)viewId { - // TODO(dkwingsmt): Fill the view ID property with the correct value once the - // iOS shell supports multiple views. - return flutter::kFlutterImplicitViewId; -} - - (void)awakeFromNib { [super awakeFromNib]; if (!_engine) { @@ -654,6 +648,12 @@ - (void)installFirstFrameCallback { #pragma mark - Properties +- (int64_t)viewId { + // TODO(dkwingsmt): Fill the view ID property with the correct value once the + // iOS shell supports multiple views. + return flutter::kFlutterImplicitViewId; +} + - (UIView*)splashScreenView { if (!_splashScreenView) { return nil; From c1330971741e7c003be873b6a1fb1431f7334f80 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 11 Dec 2023 21:56:52 -0800 Subject: [PATCH 16/23] Fix ios --- .../darwin/ios/framework/Source/FlutterViewController.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 97ee05d8f29a3..2a9af868b0c33 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -154,6 +154,7 @@ @implementation FlutterViewController { @synthesize displayingFlutterUI = _displayingFlutterUI; @synthesize prefersStatusBarHidden = _flutterPrefersStatusBarHidden; +@dynamic viewId; #pragma mark - Manage and override all designated initializers From 300292401fea60fe740fa1788d3ec746305fdb74 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 12 Dec 2023 13:25:36 -0800 Subject: [PATCH 17/23] Better id doc --- shell/platform/embedder/embedder.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 47bd83d1f7d16..45e8d83009f0d 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -266,13 +266,10 @@ typedef enum { typedef struct _FlutterEngine* FLUTTER_API_SYMBOL(FlutterEngine); -/// Identifier for views. +/// Unique identifier for views. /// -/// How view IDs are generated is decided by the embedding. The engine does not -/// assume any specifics about the generation algorithm, including whether it -/// utilizes the entire range of int64_t or permits the use of zero or negative -/// IDs. The only requirement is that at any given moment, no two views share -/// the same ID. +/// View IDs are generated by the embedder and are +/// opaque to the engine; the engine does not interpret view IDs in any way. typedef int64_t FlutterViewId; typedef struct { From e46154d68db46829b6d3181a6c36d43a813cee12 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 13 Dec 2023 01:08:33 -0800 Subject: [PATCH 18/23] Fix viewIdentifier --- .../framework/Source/FlutterViewController.mm | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 2a9af868b0c33..64d53602adebd 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -62,7 +62,7 @@ @interface FlutterViewController () (touch); - pointer_data.view_id = self.viewId; + pointer_data.view_id = self.viewIdentifier; // Pointer will be generated in pointer_data_packet_converter.cc. pointer_data.pointer_identifier = 0; @@ -2409,7 +2409,7 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer pointer_data.device = reinterpret_cast(_continuousScrollingPanGestureRecognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; pointer_data.signal_kind = flutter::PointerData::SignalKind::kScrollInertiaCancel; - pointer_data.view_id = self.viewId; + pointer_data.view_id = self.viewIdentifier; if (event.timestamp < _scrollInertiaEventAppKitDeadline) { // Only send the event if it occured before the expected natural end of gesture momentum. @@ -2433,7 +2433,7 @@ - (void)hoverEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4)) flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kMouse; - pointer_data.view_id = self.viewId; + pointer_data.view_id = self.viewIdentifier; switch (_hoverGestureRecognizer.state) { case UIGestureRecognizerStateBegan: @@ -2472,7 +2472,7 @@ - (void)hoverEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4)) inertia_cancel.device = reinterpret_cast(_continuousScrollingPanGestureRecognizer); inertia_cancel.kind = flutter::PointerData::DeviceKind::kTrackpad; inertia_cancel.signal_kind = flutter::PointerData::SignalKind::kScrollInertiaCancel; - inertia_cancel.view_id = self.viewId; + inertia_cancel.view_id = self.viewIdentifier; packet->SetPointerData(/*i=*/1, inertia_cancel); [_engine.get() dispatchPointerDataPacket:std::move(packet)]; _scrollInertiaEventStartline = DBL_MAX; @@ -2496,7 +2496,7 @@ - (void)discreteScrollEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE(io pointer_data.signal_kind = flutter::PointerData::SignalKind::kScroll; pointer_data.scroll_delta_x = (translation.x - _mouseState.last_translation.x); pointer_data.scroll_delta_y = -(translation.y - _mouseState.last_translation.y); - pointer_data.view_id = self.viewId; + pointer_data.view_id = self.viewIdentifier; // The translation reported by UIPanGestureRecognizer is the total translation // generated by the pan gesture since the gesture began. We need to be able @@ -2520,7 +2520,7 @@ - (void)continuousScrollEvent:(UIPanGestureRecognizer*)recognizer API_AVAILABLE( flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; - pointer_data.view_id = self.viewId; + pointer_data.view_id = self.viewIdentifier; switch (recognizer.state) { case UIGestureRecognizerStateBegan: pointer_data.change = flutter::PointerData::Change::kPanZoomStart; @@ -2569,7 +2569,7 @@ - (void)pinchEvent:(UIPinchGestureRecognizer*)recognizer API_AVAILABLE(ios(13.4) flutter::PointerData pointer_data = [self generatePointerDataAtLastMouseLocation]; pointer_data.device = reinterpret_cast(recognizer); pointer_data.kind = flutter::PointerData::DeviceKind::kTrackpad; - pointer_data.view_id = self.viewId; + pointer_data.view_id = self.viewIdentifier; switch (recognizer.state) { case UIGestureRecognizerStateBegan: pointer_data.change = flutter::PointerData::Change::kPanZoomStart; From 47fc6a0aa12653f8888509fd0d73ad5332913dcb Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 13 Dec 2023 01:16:16 -0800 Subject: [PATCH 19/23] mirrored var --- lib/ui/platform_dispatcher.dart | 4 +++- lib/ui/window/pointer_data.cc | 10 +++++++--- lib/ui/window/pointer_data.h | 8 +++----- .../embedding/android/AndroidTouchProcessor.java | 4 +++- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 6a52634e32a8a..ad06c933504b9 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -414,7 +414,9 @@ class PlatformDispatcher { } } - // This value must match kPointerDataFieldCount in pointer_data.cc. + // This value must match kPointerDataFieldCount in pointer_data.cc. (The + // pointer_data.cc also listed out other locations that must be kept + // consistent.) static const int _kPointerDataFieldCount = 36; static PointerDataPacket _unpackPointerDataPacket(ByteData packet) { diff --git a/lib/ui/window/pointer_data.cc b/lib/ui/window/pointer_data.cc index 704fa3a277223..e507db3337b4c 100644 --- a/lib/ui/window/pointer_data.cc +++ b/lib/ui/window/pointer_data.cc @@ -8,10 +8,14 @@ namespace flutter { -// If kPointerDataFieldCount changes, update the corresponding values in: +// The number of fields of PointerData. // -// * platform_dispatcher.dart -// * AndroidTouchProcessor.java +// If kPointerDataFieldCount changes, update the corresponding values to: +// +// * _kPointerDataFieldCount in platform_dispatcher.dart +// * POINTER_DATA_FIELD_COUNT in AndroidTouchProcessor.java +// +// (This is a centralized list of all locations that should be kept up-to-date.) static constexpr int kPointerDataFieldCount = 36; static constexpr int kBytesPerField = sizeof(int64_t); diff --git a/lib/ui/window/pointer_data.h b/lib/ui/window/pointer_data.h index 1fd139437b36c..c73081d5141c1 100644 --- a/lib/ui/window/pointer_data.h +++ b/lib/ui/window/pointer_data.h @@ -30,11 +30,9 @@ enum PointerButtonStylus : int64_t { // This structure is unpacked by platform_dispatcher.dart. // -// If this struct changes, update: -// -// * kPointerDataFieldCount in pointer_data.cc -// * the unpacking code in platform_dispatcher.dart -// * the packing code in AndroidTouchProcessor.java +// If this struct changes, update kPointerDataFieldCount in pointer_data.cc. +// (The pointer_data.cc also listed out other locations that must be kept +// consistent.) struct alignas(8) PointerData { // Must match the PointerChange enum in pointer.dart. enum class Change : int64_t { diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index 0c727c4d8fb5a..56fe9905585b7 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -80,7 +80,9 @@ public class AndroidTouchProcessor { int UNKNOWN = 4; } - // This value must match kPointerDataFieldCount in pointer_data.cc. + // This value must match kPointerDataFieldCount in pointer_data.cc. (The + // pointer_data.cc also listed out other locations that must be kept + // consistent.) private static final int POINTER_DATA_FIELD_COUNT = 36; @VisibleForTesting static final int BYTES_PER_FIELD = 8; From 7e838af006fb8f90f3cf66c1cdf5ed8d9205f9cc Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 13 Dec 2023 14:25:33 -0800 Subject: [PATCH 20/23] Fix doc --- lib/ui/platform_dispatcher.dart | 3 +-- lib/ui/window/pointer_data.h | 8 +++++--- lib/ui/window/pointer_data_packet_converter_unittests.cc | 2 ++ .../flutter/embedding/android/AndroidTouchProcessor.java | 3 +-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index ad06c933504b9..c637295b0288b 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -415,8 +415,7 @@ class PlatformDispatcher { } // This value must match kPointerDataFieldCount in pointer_data.cc. (The - // pointer_data.cc also listed out other locations that must be kept - // consistent.) + // pointer_data.cc also lists other locations that must be kept consistent.) static const int _kPointerDataFieldCount = 36; static PointerDataPacket _unpackPointerDataPacket(ByteData packet) { diff --git a/lib/ui/window/pointer_data.h b/lib/ui/window/pointer_data.h index c73081d5141c1..1fd68331bb6b1 100644 --- a/lib/ui/window/pointer_data.h +++ b/lib/ui/window/pointer_data.h @@ -30,9 +30,11 @@ enum PointerButtonStylus : int64_t { // This structure is unpacked by platform_dispatcher.dart. // -// If this struct changes, update kPointerDataFieldCount in pointer_data.cc. -// (The pointer_data.cc also listed out other locations that must be kept -// consistent.) +// If this struct changes, update: +// * kPointerDataFieldCount in pointer_data.cc. (The pointer_data.cc also +// listed out other locations that must be kept consistent.) +// * The functions to create simulated data in +// pointer_data_packet_converter_unittests.cc. struct alignas(8) PointerData { // Must match the PointerChange enum in pointer.dart. enum class Change : int64_t { diff --git a/lib/ui/window/pointer_data_packet_converter_unittests.cc b/lib/ui/window/pointer_data_packet_converter_unittests.cc index 3d6dce7571d98..d6913270b5fba 100644 --- a/lib/ui/window/pointer_data_packet_converter_unittests.cc +++ b/lib/ui/window/pointer_data_packet_converter_unittests.cc @@ -45,6 +45,7 @@ void CreateSimulatedPointerData(PointerData& data, // NOLINT data.platformData = 0; data.scroll_delta_x = 0.0; data.scroll_delta_y = 0.0; + data.view_id = 0; } void CreateSimulatedMousePointerData(PointerData& data, // NOLINT @@ -84,6 +85,7 @@ void CreateSimulatedMousePointerData(PointerData& data, // NOLINT data.platformData = 0; data.scroll_delta_x = scroll_delta_x; data.scroll_delta_y = scroll_delta_y; + data.view_id = 0; } void CreateSimulatedTrackpadGestureData(PointerData& data, // NOLINT diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index 56fe9905585b7..a920099461a8e 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -81,8 +81,7 @@ public class AndroidTouchProcessor { } // This value must match kPointerDataFieldCount in pointer_data.cc. (The - // pointer_data.cc also listed out other locations that must be kept - // consistent.) + // pointer_data.cc also lists other locations that must be kept consistent.) private static final int POINTER_DATA_FIELD_COUNT = 36; @VisibleForTesting static final int BYTES_PER_FIELD = 8; From bd1cfdbcd70500bd7b2376f65994f1a7160f43a6 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 13 Dec 2023 15:03:12 -0800 Subject: [PATCH 21/23] Add test for packing view ID --- ...pointer_data_packet_converter_unittests.cc | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/ui/window/pointer_data_packet_converter_unittests.cc b/lib/ui/window/pointer_data_packet_converter_unittests.cc index d6913270b5fba..69e43cba54fe0 100644 --- a/lib/ui/window/pointer_data_packet_converter_unittests.cc +++ b/lib/ui/window/pointer_data_packet_converter_unittests.cc @@ -716,5 +716,25 @@ TEST(PointerDataPacketConverterTest, CanConvertTrackpadGesture) { ASSERT_EQ(result[3].synthesized, 0); } +TEST(PointerDataPacketConverterTest, CanConvertViewId) { + PointerDataPacketConverter converter; + auto packet = std::make_unique(2); + PointerData data; + CreateSimulatedPointerData(data, PointerData::Change::kAdd, 0, 0.0, 0.0, 0); + data.view_id = 100; + packet->SetPointerData(0, data); + CreateSimulatedPointerData(data, PointerData::Change::kHover, 0, 1.0, 0.0, 0); + data.view_id = 200; + packet->SetPointerData(1, data); + auto converted_packet = converter.Convert(std::move(packet)); + + std::vector result; + UnpackPointerPacket(result, std::move(converted_packet)); + + ASSERT_EQ(result.size(), (size_t)2); + ASSERT_EQ(result[0].view_id, 100); + ASSERT_EQ(result[1].view_id, 200); +} + } // namespace testing } // namespace flutter From 456cebee7641ae6c3648229fe50deeddd07a1768 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 13 Dec 2023 15:04:17 -0800 Subject: [PATCH 22/23] default to implicit --- shell/platform/embedder/embedder.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index c4191dcf5226f..b165ca6c96274 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2326,7 +2326,8 @@ FlutterEngineResult FlutterEngineSendPointerEvent( pointer_data.pan_delta_y = 0.0; pointer_data.scale = SAFE_ACCESS(current, scale, 0.0); pointer_data.rotation = SAFE_ACCESS(current, rotation, 0.0); - pointer_data.view_id = SAFE_ACCESS(current, view_id, 0); + pointer_data.view_id = + SAFE_ACCESS(current, view_id, kFlutterImplicitViewId); packet->SetPointerData(i, pointer_data); current = reinterpret_cast( reinterpret_cast(current) + current->struct_size); From 713672b2885c8e5ab6f027e5432a05891de84d49 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 19 Dec 2023 13:43:29 -0800 Subject: [PATCH 23/23] Update lib/ui/window/pointer_data.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com> --- lib/ui/window/pointer_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/window/pointer_data.h b/lib/ui/window/pointer_data.h index 1fd68331bb6b1..7e18e4dae230d 100644 --- a/lib/ui/window/pointer_data.h +++ b/lib/ui/window/pointer_data.h @@ -32,7 +32,7 @@ enum PointerButtonStylus : int64_t { // // If this struct changes, update: // * kPointerDataFieldCount in pointer_data.cc. (The pointer_data.cc also -// listed out other locations that must be kept consistent.) +// lists out other locations that must be kept consistent.) // * The functions to create simulated data in // pointer_data_packet_converter_unittests.cc. struct alignas(8) PointerData {