Merge branch 'main' into srawlins-patch-1
diff --git a/DEPS b/DEPS index 325b82b..4fdea30 100644 --- a/DEPS +++ b/DEPS
@@ -14,7 +14,7 @@ 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '539ab9d398121cb2dc9a6d20a0643a59a4c15e02', + 'skia_revision': '3a081993e2a740118839621e0b0fd206e045987e', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. @@ -56,28 +56,28 @@ # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS # You can use //tools/dart/create_updated_flutter_deps.py to produce # updated revision list of existing dependencies. - 'dart_revision': 'd916a5f69a486de98316900f19ef0ff46834b03d', + 'dart_revision': '993d3069f42e98b2b29e441bc98424065cc255ca', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py - 'dart_binaryen_rev': '459bc0797f67cb2a8fd4598bb7143b34036608d9', + 'dart_binaryen_rev': '93883fde36ac158fd415dcd6dbd387dcfd928d3c', 'dart_boringssl_gen_rev': 'fef055e8d2749b82c79c8f043be1cbe5e8e4b40c', 'dart_boringssl_rev': '2db0eb3f96a5756298dcd7f9319e56a98585bd10', 'dart_browser_launcher_rev': 'e5fc5d488eb5038bfec2a6690c72ab8dd353e101', 'dart_clock_rev': '7956d60042f4ea979c4554d43eeb57d087627869', - 'dart_collection_rev': '24b75d85df6a26aac7be13b56ff1ce4360c04a64', + 'dart_collection_rev': '887b826b50f48d6a9cd2c0684aa353e8e3a0fad0', 'dart_devtools_rev': 'dcef4f6efe986f110f55dbbe7f3731802e86690a', 'dart_libprotobuf_rev': '24487dd1045c7f3d64a21f38a3f0c06cc4cf2edb', 'dart_perfetto_rev': '13ce0c9e13b0940d2476cd0cff2301708a9a2e2b', 'dart_protobuf_gn_rev': 'ca669f79945418f6229e4fef89b666b2a88cbb10', 'dart_protobuf_rev': 'ccf104dbc36929c0f8708285d5f3a8fae206343e', 'dart_pub_rev': '1efd3f5e274e153637d99698b0ee454f6f2550ab', - 'dart_tools_rev': 'd4995d47b99d5e9564abfed2218f4a23df75983b', + 'dart_tools_rev': 'f882de9ba86712003728d4663e1b73a620d352b1', 'dart_watcher_rev': '3b850778ad0b62db3aa2cfe48832870c2461db30', 'dart_web_rev': '8478cd27d574249eca3d41f9135458dfda2762c8', 'dart_webdev_rev': '5f30c560dc4e3df341356c43ec1a766ee6b74a7c', 'dart_webkit_inspection_protocol_rev': 'b459c427b74bf5e0919a083a97a167fb74d8bff1', - 'dart_yaml_edit_rev': '5c54d455f272bbb83c948ac420c677371e69ae77', + 'dart_yaml_edit_rev': '35f4248c7bbba289b3899fa55486e2f31ef1a8c5', 'ocmock_rev': 'c4ec0e3a7a9f56cfdbd0aa01f4f97bb4b75c5ef8', # v3.7.1 @@ -343,16 +343,16 @@ # WARNING: Unused Dart dependencies in the list below till "WARNING:" marker are removed automatically - see create_updated_flutter_deps.py. 'src/flutter/third_party/dart/third_party/binaryen/src': - Var('chromium_git') + '/external/github.com/WebAssembly/binaryen.git@459bc0797f67cb2a8fd4598bb7143b34036608d9', + Var('chromium_git') + '/external/github.com/WebAssembly/binaryen.git@93883fde36ac158fd415dcd6dbd387dcfd928d3c', 'src/flutter/third_party/dart/third_party/devtools': - {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:f5e84f91b32b219d646cfb87a891cd143dc84056'}]}, + {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:dcef4f6efe986f110f55dbbe7f3731802e86690a'}]}, 'src/flutter/third_party/dart/third_party/pkg/args': - Var('dart_git') + '/args.git@e623652744c82533829f2e62b1aba1a6cf06e291', + Var('dart_git') + '/args.git@09c0fca1785c9df39288a48f767994eed80bed40', 'src/flutter/third_party/dart/third_party/pkg/async': - Var('dart_git') + '/async.git@c0d81f8699682d01d657a9bf827107d11904a247', + Var('dart_git') + '/async.git@5f70a996f673d625e3502597084653686c3e754c', 'src/flutter/third_party/dart/third_party/pkg/bazel_worker': Var('dart_git') + '/bazel_worker.git@aa3cc9e826350b960e0c5a67e6065bcedba8b0ac', @@ -373,10 +373,10 @@ Var('dart_git') + '/collection.git' + '@' + Var('dart_collection_rev'), 'src/flutter/third_party/dart/third_party/pkg/convert': - Var('dart_git') + '/convert.git@9035cafefc1da4315f26058734d0c2a19d5ab56a', + Var('dart_git') + '/convert.git@d361833e117cb2438d2a2a6d0b0acb28ff0910fb', 'src/flutter/third_party/dart/third_party/pkg/crypto': - Var('dart_git') + '/crypto.git@eede7d6918c51159c1422b7449f40dbac660ee57', + Var('dart_git') + '/crypto.git@3d26ef4cf22d4b218ba30e616544ad3cf52f64a1', 'src/flutter/third_party/dart/third_party/pkg/csslib': Var('dart_git') + '/csslib.git@a3700b05bbcc42782e8a7024790dbf019d89c249', @@ -385,7 +385,7 @@ Var('dart_git') + '/dart_style.git@5d35f4d829ffb8532d345d95d3e9504ae6cd839e', 'src/flutter/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@5df03dd913a0a2e20421cac61112aa84111160e0', + Var('dart_git') + '/dartdoc.git@80c6f18f34b387d4b9ce89ddd2e3049093335f9d', 'src/flutter/third_party/dart/third_party/pkg/file': Var('dart_git') + '/external/github.com/google/file.dart@6842feaef1c4e06239bd30f8d3ef722838b1c97e', @@ -406,13 +406,13 @@ Var('dart_git') + '/http_multi_server.git@e7515b5896b83d522189802a1e14e103e19426c0', 'src/flutter/third_party/dart/third_party/pkg/http_parser': - Var('dart_git') + '/http_parser.git@ce528cf82f3d26ac761e29b2494a9e0c270d4939', + Var('dart_git') + '/http_parser.git@23d775898ee90be9daf3297e298a8869bc755d84', 'src/flutter/third_party/dart/third_party/pkg/intl': Var('dart_git') + '/intl.git@5d65e3808ce40e6282e40881492607df4e35669f', 'src/flutter/third_party/dart/third_party/pkg/json_rpc_2': - Var('dart_git') + '/json_rpc_2.git@b4810dc7bee5828f240586c81f3f34853cacdbce', + Var('dart_git') + '/json_rpc_2.git@c9b616bded8cdb5bfdc836ba7648afa6aba40062', 'src/flutter/third_party/dart/third_party/pkg/leak_tracker': Var('dart_git') + '/leak_tracker.git@f5620600a5ce1c44f65ddaa02001e200b096e14c', @@ -427,7 +427,7 @@ Var('dart_git') + '/matcher.git@31f13583630e093731c8cf2b843c14196d748c5c', 'src/flutter/third_party/dart/third_party/pkg/mockito': - Var('dart_git') + '/mockito.git@3de67548e833a8eef66a2a49070b197c2c08b3ab', + Var('dart_git') + '/mockito.git@57d484f9b8e7f6a504966a901174358a42fa932a', 'src/flutter/third_party/dart/third_party/pkg/native': Var('dart_git') + '/native.git@659511886501bcce638c3966590df04984909ef0', @@ -439,7 +439,7 @@ Var('dart_git') + '/path.git@e969f42ed112dd702a9453beb9df6c12ae2d3805', 'src/flutter/third_party/dart/third_party/pkg/pool': - Var('dart_git') + '/pool.git@924fb04353cec915d927f9f1aed88e2eda92b98a', + Var('dart_git') + '/pool.git@7bfc71b39742753a88688e56e55a828a2f5dc0bf', 'src/flutter/third_party/dart/third_party/pkg/protobuf': Var('dart_git') + '/protobuf.git' + '@' + Var('dart_protobuf_rev'), @@ -469,10 +469,10 @@ Var('dart_git') + '/stream_channel.git@f4407168b275fcde9187baefd7dbce76d0992825', 'src/flutter/third_party/dart/third_party/pkg/string_scanner': - Var('dart_git') + '/string_scanner.git@2139417ffcd0392bde3ba9bc83ee13eaa5fbed01', + Var('dart_git') + '/string_scanner.git@084b201c54b168aced178fff41fce71e3869ae42', 'src/flutter/third_party/dart/third_party/pkg/tar': - Var('dart_git') + '/external/github.com/simolus3/tar.git@32ceb55e673141abff4e84b99483fe5eb881c291', + Var('dart_git') + '/external/github.com/simolus3/tar.git@5a1ea943e70cdf3fa5e1102cdbb9418bd9b4b81a', 'src/flutter/third_party/dart/third_party/pkg/term_glyph': Var('dart_git') + '/term_glyph.git@19d8c08a4e81122639129c62049896021910c932', @@ -487,7 +487,7 @@ Var('dart_git') + '/tools.git' + '@' + Var('dart_tools_rev'), 'src/flutter/third_party/dart/third_party/pkg/typed_data': - Var('dart_git') + '/typed_data.git@2bb9e6ead6394e2d4ec6068c5ece8b2ec0e2b945', + Var('dart_git') + '/typed_data.git@6abfafdcf661cd8a814619d7e2a3e99edb3a3862', 'src/flutter/third_party/dart/third_party/pkg/watcher': Var('dart_git') + '/watcher.git' + '@' + Var('dart_watcher_rev'), @@ -496,7 +496,7 @@ Var('dart_git') + '/web.git' + '@' + Var('dart_web_rev'), 'src/flutter/third_party/dart/third_party/pkg/web_socket_channel': - Var('dart_git') + '/web_socket_channel.git@0e1d6e2eb5a0bfd62e45b772ac7107d796176cf6', + Var('dart_git') + '/web_socket_channel.git@40aa29f1d2167467f5934d755891a8beb62a1239', 'src/flutter/third_party/dart/third_party/pkg/webdev': Var('dart_git') + '/webdev.git' + '@' + Var('dart_webdev_rev'), @@ -956,7 +956,7 @@ 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'T2Cq00sVabK2fCW9rsjkaWqRxX6RLvKGTNya2LeZ2MAC' + 'version': '9F_NaKPd2twhbPwP7A4a6UlWT-_f9PVyLrS8ZFo-3UkC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk',
diff --git a/analysis_options.yaml b/analysis_options.yaml index 771f879..248a9f2 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml
@@ -212,7 +212,9 @@ - unnecessary_null_in_if_null_operators - unnecessary_nullable_for_final_variable_declarations - unnecessary_overrides - - unnecessary_parenthesis + # TODO(zanderso): Temporarily disabling to unblock a Dart -> Engine roll. + # https://github.com/flutter/engine/pull/55927. + # - unnecessary_parenthesis # - unnecessary_raw_strings # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint - unnecessary_statements - unnecessary_string_escapes
diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index b70659a..993fc88 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files
@@ -1444,6 +1444,11 @@ ../../../flutter/third_party/dart/runtime/tools/heapsnapshot/README.md ../../../flutter/third_party/dart/runtime/tools/heapsnapshot/pubspec.yaml ../../../flutter/third_party/dart/runtime/tools/heapsnapshot/test +../../../flutter/third_party/dart/runtime/tools/profiling/.gitignore +../../../flutter/third_party/dart/runtime/tools/profiling/CHANGELOG.md +../../../flutter/third_party/dart/runtime/tools/profiling/README.md +../../../flutter/third_party/dart/runtime/tools/profiling/analysis_options.yaml +../../../flutter/third_party/dart/runtime/tools/profiling/pubspec.yaml ../../../flutter/third_party/dart/runtime/tools/utils.py ../../../flutter/third_party/dart/runtime/tools/valgrind.py ../../../flutter/third_party/dart/runtime/tools/wiki/README.md @@ -1490,6 +1495,7 @@ ../../../flutter/third_party/dart/runtime/vm/compiler/backend/locations_helpers_test.cc ../../../flutter/third_party/dart/runtime/vm/compiler/backend/loops_test.cc ../../../flutter/third_party/dart/runtime/vm/compiler/backend/memory_copy_test.cc +../../../flutter/third_party/dart/runtime/vm/compiler/backend/pragma_unsafe_no_bounds_check_test.cc ../../../flutter/third_party/dart/runtime/vm/compiler/backend/range_analysis_test.cc ../../../flutter/third_party/dart/runtime/vm/compiler/backend/reachability_fence_test.cc ../../../flutter/third_party/dart/runtime/vm/compiler/backend/redundancy_elimination_test.cc @@ -1565,7 +1571,7 @@ ../../../flutter/third_party/dart/runtime/vm/port_test.cc ../../../flutter/third_party/dart/runtime/vm/profiler_test.cc ../../../flutter/third_party/dart/runtime/vm/protos/.gitignore -../../../flutter/third_party/dart/runtime/vm/regexp_test.cc +../../../flutter/third_party/dart/runtime/vm/regexp/regexp_test.cc ../../../flutter/third_party/dart/runtime/vm/ring_buffer_test.cc ../../../flutter/third_party/dart/runtime/vm/scopes_test.cc ../../../flutter/third_party/dart/runtime/vm/service
diff --git a/ci/licenses_golden/licenses_dart b/ci/licenses_golden/licenses_dart index 6ec669e..7d85232 100644 --- a/ci/licenses_golden/licenses_dart +++ b/ci/licenses_golden/licenses_dart
@@ -1,7 +1,8 @@ -Signature: 125335ea80d045b9f6f1a902f51abbc7 +Signature: 29033265e95e2a79cca60a10ae90b328 ==================================================================================================== LIBRARY: dart +ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/pprof/profile.proto ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/dart/runtime/vm/protos/perfetto/common/builtin_clock.proto ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/dart/runtime/vm/protos/perfetto/trace/clock_snapshot.proto ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/dart/runtime/vm/protos/perfetto/trace/interned_data/interned_data.proto @@ -15,6 +16,7 @@ ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/dart/runtime/vm/protos/perfetto/trace/track_event/track_descriptor.proto ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/dart/runtime/vm/protos/perfetto/trace/track_event/track_event.proto TYPE: LicenseType.apache +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/pprof/profile.proto FILE: ../../../flutter/third_party/dart/runtime/vm/protos/perfetto/common/builtin_clock.proto FILE: ../../../flutter/third_party/dart/runtime/vm/protos/perfetto/trace/clock_snapshot.proto FILE: ../../../flutter/third_party/dart/runtime/vm/protos/perfetto/trace/interned_data/interned_data.proto @@ -1924,16 +1926,19 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/vm/metrics.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/object_graph.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/object_graph.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_ir.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_ir.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_ast.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_ast.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_parser.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_parser.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_ir.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_ir.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_ast.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_ast.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_parser.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_parser.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/unibrow-inl.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/unibrow.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/unibrow.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/report.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/report.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/ring_buffer.h + ../../../flutter/third_party/dart/LICENSE @@ -1942,9 +1947,6 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/vm/simulator_arm64.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/stack_frame_arm64.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/tags.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/unibrow-inl.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/unibrow.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/unibrow.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_dev_runtime/private/preambles/d8.js + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_dev_runtime/private/preambles/jsshell.js + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart + ../../../flutter/third_party/dart/LICENSE @@ -2016,16 +2018,19 @@ FILE: ../../../flutter/third_party/dart/runtime/vm/metrics.h FILE: ../../../flutter/third_party/dart/runtime/vm/object_graph.cc FILE: ../../../flutter/third_party/dart/runtime/vm/object_graph.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_ir.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_ir.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_ast.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_ast.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_parser.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_parser.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_ir.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_ir.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_ast.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_ast.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_parser.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_parser.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/unibrow-inl.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/unibrow.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/unibrow.h FILE: ../../../flutter/third_party/dart/runtime/vm/report.cc FILE: ../../../flutter/third_party/dart/runtime/vm/report.h FILE: ../../../flutter/third_party/dart/runtime/vm/ring_buffer.h @@ -2034,9 +2039,6 @@ FILE: ../../../flutter/third_party/dart/runtime/vm/simulator_arm64.h FILE: ../../../flutter/third_party/dart/runtime/vm/stack_frame_arm64.h FILE: ../../../flutter/third_party/dart/runtime/vm/tags.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/unibrow-inl.h -FILE: ../../../flutter/third_party/dart/runtime/vm/unibrow.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/unibrow.h FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_dev_runtime/private/preambles/d8.js FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_dev_runtime/private/preambles/jsshell.js FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart @@ -2116,12 +2118,12 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/vm/profiler_service.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/program_visitor.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/program_visitor.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_bytecode.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_bytecode.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_bytecode_inl.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_bytecodes.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_interpreter.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp_interpreter.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_bytecode.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_bytecode.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_bytecode_inl.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_bytecodes.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_interpreter.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_interpreter.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/scope_timer.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/service_event.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/service_event.h + ../../../flutter/third_party/dart/LICENSE @@ -2195,12 +2197,12 @@ FILE: ../../../flutter/third_party/dart/runtime/vm/profiler_service.h FILE: ../../../flutter/third_party/dart/runtime/vm/program_visitor.cc FILE: ../../../flutter/third_party/dart/runtime/vm/program_visitor.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_bytecode.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_bytecode.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_assembler_bytecode_inl.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_bytecodes.h -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_interpreter.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/regexp_interpreter.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_bytecode.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_bytecode.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_assembler_bytecode_inl.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_bytecodes.h +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_interpreter.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/regexp_interpreter.h FILE: ../../../flutter/third_party/dart/runtime/vm/scope_timer.h FILE: ../../../flutter/third_party/dart/runtime/vm/service_event.cc FILE: ../../../flutter/third_party/dart/runtime/vm/service_event.h @@ -4074,6 +4076,11 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/platform/synchronization_win.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/platform/threads.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/tools/dartfuzz/flag_fuzzer.dart + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/tools/profiling/bin/convert_allocation_profile.dart + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/tools/profiling/bin/set_uprobe.dart + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/elf_utils.dart + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/perf/perf_data.dart + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/symbols.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/bytecode_reader.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/bytecode_reader.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/compiler/assembler/disassembler_kbc.cc + ../../../flutter/third_party/dart/LICENSE @@ -4120,6 +4127,11 @@ FILE: ../../../flutter/third_party/dart/runtime/platform/synchronization_win.cc FILE: ../../../flutter/third_party/dart/runtime/platform/threads.h FILE: ../../../flutter/third_party/dart/runtime/tools/dartfuzz/flag_fuzzer.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/bin/convert_allocation_profile.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/bin/set_uprobe.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/elf_utils.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/perf/perf_data.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/symbols.dart FILE: ../../../flutter/third_party/dart/runtime/vm/bytecode_reader.cc FILE: ../../../flutter/third_party/dart/runtime/vm/bytecode_reader.h FILE: ../../../flutter/third_party/dart/runtime/vm/compiler/assembler/disassembler_kbc.cc @@ -4371,6 +4383,10 @@ FILE: ../../../flutter/third_party/dart/runtime/tools/entitlements/gen_snapshot.plist FILE: ../../../flutter/third_party/dart/runtime/tools/entitlements/gen_snapshot_product.plist FILE: ../../../flutter/third_party/dart/runtime/tools/entitlements/run_vm_tests.plist +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/pprof/generated/profile.pb.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/pprof/generated/profile.pbenum.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/pprof/generated/profile.pbjson.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/profiling/lib/src/pprof/generated/profile.pbserver.dart FILE: ../../../flutter/third_party/dart/runtime/tools/wiki/styles/style.scss FILE: ../../../flutter/third_party/dart/runtime/tools/wiki/templates/includes/auto-refresh.html FILE: ../../../flutter/third_party/dart/runtime/tools/wiki/templates/page.html @@ -4787,7 +4803,7 @@ This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/115a3c609bf22d78d532ea9a9ecbcfb11ca9764f +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/993d3069f42e98b2b29e441bc98424065cc255ca /third_party/fallback_root_certificates/ ====================================================================================================
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index fd9a96d..283a93a 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter
@@ -44799,6 +44799,9 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_layout.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_layout.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_layout_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc + ../../../flutter/LICENSE @@ -47699,6 +47702,9 @@ FILE: ../../../flutter/shell/platform/linux/fl_keyboard_layout.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_layout.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_layout_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.h +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager_test.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc
diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index d4b5ecb..4d22975 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia
@@ -1,4 +1,4 @@ -Signature: 147bb5b1f6ce1d858d13c192ce702004 +Signature: e6795c8a2a5ff5824f7e5b3c503cf201 ==================================================================================================== LIBRARY: fuchsia_sdk @@ -14859,7 +14859,6 @@ ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/exception.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/functional.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/span.h + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/tuple.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/type_traits.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/iterator.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/span.h + ../../../fuchsia/sdk/linux/LICENSE @@ -15042,7 +15041,6 @@ FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/exception.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/functional.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/span.h -FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/tuple.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/type_traits.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/iterator.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/span.h @@ -15415,7 +15413,6 @@ ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp_testing/fake_flatland.cc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp_testing/fake_flatland_types.cc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/linkage.h + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/variant.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/sys/component/realm_builder_absolute.shard.cml + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/sys/component/realm_builder_base.shard.cml + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/sys_component_cpp_testing/internal/convert.cc + ../../../fuchsia/sdk/linux/LICENSE @@ -15769,7 +15766,6 @@ FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp_testing/fake_flatland.cc FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp_testing/fake_flatland_types.cc FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/linkage.h -FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/variant.h FILE: ../../../fuchsia/sdk/linux/pkg/sys/component/realm_builder_absolute.shard.cml FILE: ../../../fuchsia/sdk/linux/pkg/sys/component/realm_builder_base.shard.cml FILE: ../../../fuchsia/sdk/linux/pkg/sys_component_cpp_testing/internal/convert.cc @@ -16126,6 +16122,8 @@ ORIGIN: ../../../fuchsia/sdk/linux/obj/x64-api-23/sysroot/include/zircon/availability_levels.inc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/obj/x64-api-24/sysroot/include/zircon/availability_levels.inc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/obj/x64-api-NEXT/sysroot/include/zircon/availability_levels.inc + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/pkg/driver_incoming_cpp/include/lib/driver/incoming/cpp/service_validator.h + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/pkg/driver_incoming_cpp/service_validator.cc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/driver_metadata_cpp/include/lib/driver/metadata/cpp/metadata.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/driver_metadata_cpp/include/lib/driver/metadata/cpp/metadata_server.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/driver_node_cpp/add_child.cc + ../../../fuchsia/sdk/linux/LICENSE @@ -16148,6 +16146,7 @@ ORIGIN: ../../../fuchsia/sdk/linux/pkg/syslog_cpp/include/lib/syslog/cpp/log_message_impl.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/syslog_cpp/log_message_impl.cc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/vulkan/offer.shard.cml + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/pkg/zx/time.cc + ../../../fuchsia/sdk/linux/LICENSE TYPE: LicenseType.bsd FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/availability_levels.inc FILE: ../../../fuchsia/sdk/linux/arch/riscv64/sysroot/include/zircon/availability_levels.inc @@ -16208,6 +16207,8 @@ FILE: ../../../fuchsia/sdk/linux/obj/x64-api-23/sysroot/include/zircon/availability_levels.inc FILE: ../../../fuchsia/sdk/linux/obj/x64-api-24/sysroot/include/zircon/availability_levels.inc FILE: ../../../fuchsia/sdk/linux/obj/x64-api-NEXT/sysroot/include/zircon/availability_levels.inc +FILE: ../../../fuchsia/sdk/linux/pkg/driver_incoming_cpp/include/lib/driver/incoming/cpp/service_validator.h +FILE: ../../../fuchsia/sdk/linux/pkg/driver_incoming_cpp/service_validator.cc FILE: ../../../fuchsia/sdk/linux/pkg/driver_metadata_cpp/include/lib/driver/metadata/cpp/metadata.h FILE: ../../../fuchsia/sdk/linux/pkg/driver_metadata_cpp/include/lib/driver/metadata/cpp/metadata_server.h FILE: ../../../fuchsia/sdk/linux/pkg/driver_node_cpp/add_child.cc @@ -16230,6 +16231,7 @@ FILE: ../../../fuchsia/sdk/linux/pkg/syslog_cpp/include/lib/syslog/cpp/log_message_impl.h FILE: ../../../fuchsia/sdk/linux/pkg/syslog_cpp/log_message_impl.cc FILE: ../../../fuchsia/sdk/linux/pkg/vulkan/offer.shard.cml +FILE: ../../../fuchsia/sdk/linux/pkg/zx/time.cc ---------------------------------------------------------------------------------------------------- Copyright 2024 The Fuchsia Authors. All rights reserved.
diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 844c362..a96a0bb 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia
@@ -1,4 +1,4 @@ -Signature: 015672489e829391bd5d2de2efd67231 +Signature: 83c4ecafc6e635226445e328864ab843 ==================================================================================================== LIBRARY: etc1
diff --git a/impeller/core/device_buffer.h b/impeller/core/device_buffer.h index 07dba77..7fa2f3e 100644 --- a/impeller/core/device_buffer.h +++ b/impeller/core/device_buffer.h
@@ -23,9 +23,9 @@ Range source_range, size_t offset = 0u); - virtual bool SetLabel(const std::string& label) = 0; + virtual bool SetLabel(std::string_view label) = 0; - virtual bool SetLabel(const std::string& label, Range range) = 0; + virtual bool SetLabel(std::string_view label, Range range) = 0; /// @brief Create a buffer view of this entire buffer. static BufferView AsBufferView(std::shared_ptr<DeviceBuffer> buffer);
diff --git a/impeller/core/host_buffer.cc b/impeller/core/host_buffer.cc index 69b8c1c..1bee375 100644 --- a/impeller/core/host_buffer.cc +++ b/impeller/core/host_buffer.cc
@@ -37,10 +37,6 @@ HostBuffer::~HostBuffer() = default; -void HostBuffer::SetLabel(std::string label) { - label_ = std::move(label); -} - BufferView HostBuffer::Emplace(const void* buffer, size_t length, size_t align) {
diff --git a/impeller/core/host_buffer.h b/impeller/core/host_buffer.h index 90ab30d..43c03c3 100644 --- a/impeller/core/host_buffer.h +++ b/impeller/core/host_buffer.h
@@ -30,10 +30,7 @@ static std::shared_ptr<HostBuffer> Create( const std::shared_ptr<Allocator>& allocator); - // |Buffer| - virtual ~HostBuffer(); - - void SetLabel(std::string label); + ~HostBuffer(); //---------------------------------------------------------------------------- /// @brief Emplace uniform data onto the host buffer. Ensure that backend @@ -169,7 +166,6 @@ size_t current_buffer_ = 0u; size_t offset_ = 0u; size_t frame_index_ = 0u; - std::string label_; }; } // namespace impeller
diff --git a/impeller/display_list/aiks_dl_basic_unittests.cc b/impeller/display_list/aiks_dl_basic_unittests.cc index 4dcfc75..39e5d05 100644 --- a/impeller/display_list/aiks_dl_basic_unittests.cc +++ b/impeller/display_list/aiks_dl_basic_unittests.cc
@@ -94,7 +94,7 @@ namespace { bool GenerateMipmap(const std::shared_ptr<Context>& context, std::shared_ptr<Texture> texture, - std::string label) { + std::string_view label) { auto buffer = context->CreateCommandBuffer(); if (!buffer) { return false; @@ -103,7 +103,7 @@ if (!pass) { return false; } - pass->GenerateMipmap(std::move(texture), std::move(label)); + pass->GenerateMipmap(std::move(texture), label); pass->EncodeCommands(context->GetResourceAllocator()); return context->GetCommandQueue()->Submit({buffer}).ok();
diff --git a/impeller/display_list/aiks_dl_blend_unittests.cc b/impeller/display_list/aiks_dl_blend_unittests.cc index 41c57e8..f4691f6 100644 --- a/impeller/display_list/aiks_dl_blend_unittests.cc +++ b/impeller/display_list/aiks_dl_blend_unittests.cc
@@ -888,5 +888,22 @@ ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(AiksTest, DestructiveBlendColorFilterFloodsClip) { + DisplayListBuilder builder; + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + builder.DrawPaint(paint); + + DlPaint save_paint; + save_paint.setColorFilter( + DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kSrc)); + builder.SaveLayer(nullptr, &save_paint); + builder.Restore(); + + // Should be solid red as the destructive color filter floods the clip. + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller
diff --git a/impeller/display_list/aiks_dl_unittests.cc b/impeller/display_list/aiks_dl_unittests.cc index 236345f..279b7bc 100644 --- a/impeller/display_list/aiks_dl_unittests.cc +++ b/impeller/display_list/aiks_dl_unittests.cc
@@ -160,12 +160,15 @@ paint.setColor(DlColor::kBlack().withAlpha(128)); paint.setColorFilter( DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kDstOver)); + builder.Save(); + builder.ClipRect(SkRect::MakeXYWH(100, 500, 300, 300)); builder.SaveLayer(nullptr, &paint); DlPaint draw_paint; draw_paint.setColor(DlColor::kBlue()); builder.DrawRect(SkRect::MakeXYWH(100, 500, 300, 300), draw_paint); builder.Restore(); + builder.Restore(); ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } @@ -203,12 +206,15 @@ save_paint.setColor(DlColor::kBlack().withAlpha(128)); save_paint.setColorFilter( DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kDstOver)); + builder.Save(); + builder.ClipRect(SkRect::MakeXYWH(100, 500, 300, 300)); builder.SaveLayer(nullptr, &save_paint); DlPaint draw_paint; draw_paint.setColor(DlColor::kBlue()); builder.DrawRect(SkRect::MakeXYWH(100, 500, 300, 300), draw_paint); builder.Restore(); + builder.Restore(); ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); }
diff --git a/impeller/display_list/canvas.cc b/impeller/display_list/canvas.cc index d14db69..dedb9c3 100644 --- a/impeller/display_list/canvas.cc +++ b/impeller/display_list/canvas.cc
@@ -1015,7 +1015,9 @@ filter_contents, // /*flood_output_coverage=*/ Entity::IsBlendModeDestructive(paint.blend_mode), // - /*flood_input_coverage=*/!!backdrop_filter // + /*flood_input_coverage=*/!!backdrop_filter || + (paint.color_filter && + paint.color_filter->modifies_transparent_black()) // ); if (!maybe_subpass_coverage.has_value()) {
diff --git a/impeller/entity/contents/atlas_contents.cc b/impeller/entity/contents/atlas_contents.cc index 19053b0..3addc0b 100644 --- a/impeller/entity/contents/atlas_contents.cc +++ b/impeller/entity/contents/atlas_contents.cc
@@ -94,8 +94,7 @@ using FS = PorterDuffBlendPipeline::FragmentShader; #ifdef IMPELLER_DEBUG - pass.SetCommandLabel( - SPrintF("DrawAtlas Blend (%s)", BlendModeToString(blend_mode))); + pass.SetCommandLabel("DrawAtlas Blend"); #endif // IMPELLER_DEBUG pass.SetVertexBuffer(geometry_->CreateBlendVertexBuffer(host_buffer)); pass.SetPipeline( @@ -138,8 +137,7 @@ using FS = VerticesUberShader::FragmentShader; #ifdef IMPELLER_DEBUG - pass.SetCommandLabel( - SPrintF("DrawAtlas Advanced Blend (%s)", BlendModeToString(blend_mode))); + pass.SetCommandLabel("DrawAtlas Advanced Blend"); #endif // IMPELLER_DEBUG pass.SetVertexBuffer(geometry_->CreateBlendVertexBuffer(host_buffer));
diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index a563c2c..70d1df7 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc
@@ -493,12 +493,12 @@ if (context->GetCapabilities()->SupportsOffscreenMSAA() && msaa_enabled) { subpass_target = GetRenderTargetCache()->CreateOffscreenMSAA( *context, texture_size, - /*mip_count=*/mip_count, SPrintF("%s Offscreen", label.data()), + /*mip_count=*/mip_count, label, RenderTarget::kDefaultColorAttachmentConfigMSAA, depth_stencil_config); } else { subpass_target = GetRenderTargetCache()->CreateOffscreen( *context, texture_size, - /*mip_count=*/mip_count, SPrintF("%s Offscreen", label.data()), + /*mip_count=*/mip_count, label, RenderTarget::kDefaultColorAttachmentConfig, depth_stencil_config); } return MakeSubpass(label, subpass_target, command_buffer, subpass_callback); @@ -520,7 +520,7 @@ if (!sub_renderpass) { return fml::Status(fml::StatusCode::kUnknown, ""); } - sub_renderpass->SetLabel(SPrintF("%s RenderPass", label.data())); + sub_renderpass->SetLabel(label); if (!subpass_callback(*this, *sub_renderpass)) { return fml::Status(fml::StatusCode::kUnknown, "");
diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index c2fe1fc..9abdc51 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h
@@ -992,7 +992,7 @@ PipelineDescriptor& desc) { opts.ApplyToPipelineDescriptor(desc); desc.SetLabel( - SPrintF("%s V#%zu", desc.GetLabel().c_str(), variants_count)); + SPrintF("%s V#%zu", desc.GetLabel().data(), variants_count)); }); std::unique_ptr<RenderPipelineHandleT> variant = std::make_unique<RenderPipelineHandleT>(std::move(variant_future));
diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index d2e39ea..b70c717 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
@@ -239,7 +239,7 @@ // .Contains(coverage_hint.value())) std::optional<Rect> snapshot_coverage = input_snapshot.GetCoverage(); - if (input_snapshot.transform.IsIdentity() && + if (input_snapshot.transform.Equals(snapshot_entity.GetTransform()) && source_expanded_coverage_hint.has_value() && snapshot_coverage.has_value() && snapshot_coverage->Contains(source_expanded_coverage_hint.value())) {
diff --git a/impeller/entity/contents/test/recording_render_pass.cc b/impeller/entity/contents/test/recording_render_pass.cc index dcc35cc..da36a5f 100644 --- a/impeller/entity/contents/test/recording_render_pass.cc +++ b/impeller/entity/contents/test/recording_render_pass.cc
@@ -92,7 +92,7 @@ } // |RenderPass| -void RecordingRenderPass::OnSetLabel(std::string label) { +void RecordingRenderPass::OnSetLabel(std::string_view label) { return; }
diff --git a/impeller/entity/contents/test/recording_render_pass.h b/impeller/entity/contents/test/recording_render_pass.h index 12fd10c..ffbef6f 100644 --- a/impeller/entity/contents/test/recording_render_pass.h +++ b/impeller/entity/contents/test/recording_render_pass.h
@@ -69,7 +69,7 @@ const std::unique_ptr<const Sampler>& sampler) override; // |RenderPass| - void OnSetLabel(std::string label) override; + void OnSetLabel(std::string_view label) override; // |RenderPass| bool OnEncodeCommands(const Context& context) const override;
diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc index f23d39f..f443558 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc
@@ -31,8 +31,8 @@ return contents; } -void TextureContents::SetLabel(std::string label) { - label_ = std::move(label); +void TextureContents::SetLabel(std::string_view label) { + label_ = label; } void TextureContents::SetDestinationRect(Rect rect) {
diff --git a/impeller/entity/contents/texture_contents.h b/impeller/entity/contents/texture_contents.h index 2526eab..34657ff 100644 --- a/impeller/entity/contents/texture_contents.h +++ b/impeller/entity/contents/texture_contents.h
@@ -25,7 +25,7 @@ /// when image filters are applied. static std::shared_ptr<TextureContents> MakeRect(Rect destination); - void SetLabel(std::string label); + void SetLabel(std::string_view label); void SetDestinationRect(Rect rect);
diff --git a/impeller/entity/render_target_cache.cc b/impeller/entity/render_target_cache.cc index c96dc6a..dbfe0a9 100644 --- a/impeller/entity/render_target_cache.cc +++ b/impeller/entity/render_target_cache.cc
@@ -31,7 +31,7 @@ const Context& context, ISize size, int mip_count, - const std::string& label, + std::string_view label, RenderTarget::AttachmentConfig color_attachment_config, std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config, const std::shared_ptr<Texture>& existing_color_texture, @@ -79,7 +79,7 @@ const Context& context, ISize size, int mip_count, - const std::string& label, + std::string_view label, RenderTarget::AttachmentConfigMSAA color_attachment_config, std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config, const std::shared_ptr<Texture>& existing_color_msaa_texture,
diff --git a/impeller/entity/render_target_cache.h b/impeller/entity/render_target_cache.h index 838814e..7c7f914 100644 --- a/impeller/entity/render_target_cache.h +++ b/impeller/entity/render_target_cache.h
@@ -5,6 +5,7 @@ #ifndef FLUTTER_IMPELLER_ENTITY_RENDER_TARGET_CACHE_H_ #define FLUTTER_IMPELLER_ENTITY_RENDER_TARGET_CACHE_H_ +#include <string_view> #include "impeller/renderer/render_target.h" namespace impeller { @@ -29,7 +30,7 @@ const Context& context, ISize size, int mip_count, - const std::string& label = "Offscreen", + std::string_view label = "Offscreen", RenderTarget::AttachmentConfig color_attachment_config = RenderTarget::kDefaultColorAttachmentConfig, std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config = @@ -42,7 +43,7 @@ const Context& context, ISize size, int mip_count, - const std::string& label = "Offscreen MSAA", + std::string_view label = "Offscreen MSAA", RenderTarget::AttachmentConfigMSAA color_attachment_config = RenderTarget::kDefaultColorAttachmentConfigMSAA, std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config =
diff --git a/impeller/entity/save_layer_utils.cc b/impeller/entity/save_layer_utils.cc index 6c9e528..3049902 100644 --- a/impeller/entity/save_layer_utils.cc +++ b/impeller/entity/save_layer_utils.cc
@@ -25,11 +25,8 @@ // first is the presence of a backdrop filter on the saveLayer. The second is // the presence of a color filter that effects transparent black on the // saveLayer. The last is the presence of unbounded content within the - // saveLayer (such as a drawPaint, bdf, et cetera). Note that currently - // only the presence of a backdrop filter impacts this flag, while color - // filters are not yet handled - // (https://github.com/flutter/flutter/issues/154035) and unbounded coverage - // is handled in the display list dispatcher. + // saveLayer (such as a drawPaint, bdf, et cetera). Note that unbounded + // coverage is handled in the display list dispatcher. // // Backdrop filters apply before the saveLayer is restored. The presence of // a backdrop filter causes the content coverage of the saveLayer to be
diff --git a/impeller/geometry/matrix.h b/impeller/geometry/matrix.h index 1726c30..166fc11 100644 --- a/impeller/geometry/matrix.h +++ b/impeller/geometry/matrix.h
@@ -407,6 +407,27 @@ std::optional<MatrixDecomposition> Decompose() const; + bool Equals(const Matrix& matrix, Scalar epsilon = 1e-5f) const { + const Scalar* a = m; + const Scalar* b = matrix.m; + return ScalarNearlyEqual(a[0], b[0], epsilon) && + ScalarNearlyEqual(a[1], b[1], epsilon) && + ScalarNearlyEqual(a[2], b[2], epsilon) && + ScalarNearlyEqual(a[3], b[3], epsilon) && + ScalarNearlyEqual(a[4], b[4], epsilon) && + ScalarNearlyEqual(a[5], b[5], epsilon) && + ScalarNearlyEqual(a[6], b[6], epsilon) && + ScalarNearlyEqual(a[7], b[7], epsilon) && + ScalarNearlyEqual(a[8], b[8], epsilon) && + ScalarNearlyEqual(a[9], b[9], epsilon) && + ScalarNearlyEqual(a[10], b[10], epsilon) && + ScalarNearlyEqual(a[11], b[11], epsilon) && + ScalarNearlyEqual(a[12], b[12], epsilon) && + ScalarNearlyEqual(a[13], b[13], epsilon) && + ScalarNearlyEqual(a[14], b[14], epsilon) && + ScalarNearlyEqual(a[15], b[15], epsilon); + } + constexpr bool operator==(const Matrix& m) const { // clang-format off return vec[0] == m.vec[0]
diff --git a/impeller/geometry/matrix_unittests.cc b/impeller/geometry/matrix_unittests.cc index ac16008..91a2a50 100644 --- a/impeller/geometry/matrix_unittests.cc +++ b/impeller/geometry/matrix_unittests.cc
@@ -25,6 +25,18 @@ 11.0, 21.0, 0.0, 1.0))); } +TEST(MatrixTest, Equals) { + Matrix x; + Matrix y = x; + EXPECT_TRUE(x.Equals(y)); +} + +TEST(MatrixTest, NotEquals) { + Matrix x; + Matrix y = x.Translate({1, 0, 0}); + EXPECT_FALSE(x.Equals(y)); +} + TEST(MatrixTest, HasPerspective2D) { EXPECT_FALSE(Matrix().HasPerspective2D());
diff --git a/impeller/geometry/scalar.h b/impeller/geometry/scalar.h index 2600a49..dadc528 100644 --- a/impeller/geometry/scalar.h +++ b/impeller/geometry/scalar.h
@@ -22,6 +22,11 @@ return val >= T{} ? val : -val; } +template <> +constexpr Scalar Absolute<Scalar>(const float& val) { + return fabsf(val); +} + constexpr inline bool ScalarNearlyZero(Scalar x, Scalar tolerance = kEhCloseEnough) { return Absolute(x) <= tolerance;
diff --git a/impeller/renderer/backend/gles/blit_command_gles.cc b/impeller/renderer/backend/gles/blit_command_gles.cc index 9d20a01..04f6c4a 100644 --- a/impeller/renderer/backend/gles/blit_command_gles.cc +++ b/impeller/renderer/backend/gles/blit_command_gles.cc
@@ -73,7 +73,7 @@ // glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to // emulate the blit when it's not available in the driver. if (!gl.BlitFramebuffer.IsAvailable()) { - // TODO(135818): Emulate the blit using a raster draw call here. + // TODO(157064): Emulate the blit using a raster draw call here. VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2."; return false; } @@ -367,7 +367,7 @@ // glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to // emulate the blit when it's not available in the driver. if (!gl.BlitFramebuffer.IsAvailable()) { - // TODO(135818): Emulate the blit using a raster draw call here. + // TODO(157064): Emulate the blit using a raster draw call here. VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2."; return false; }
diff --git a/impeller/renderer/backend/gles/blit_pass_gles.cc b/impeller/renderer/backend/gles/blit_pass_gles.cc index 39d963d..94d8300 100644 --- a/impeller/renderer/backend/gles/blit_pass_gles.cc +++ b/impeller/renderer/backend/gles/blit_pass_gles.cc
@@ -27,8 +27,8 @@ } // |BlitPass| -void BlitPassGLES::OnSetLabel(std::string label) { - label_ = std::move(label); +void BlitPassGLES::OnSetLabel(std::string_view label) { + label_ = std::string(label); } [[nodiscard]] bool EncodeCommandsInReactor( @@ -96,7 +96,7 @@ std::shared_ptr<Texture> destination, IRect source_region, IPoint destination_origin, - std::string label) { + std::string_view label) { auto command = std::make_unique<BlitCopyTextureToTextureCommandGLES>(); command->label = label; command->source = std::move(source); @@ -114,7 +114,7 @@ std::shared_ptr<DeviceBuffer> destination, IRect source_region, size_t destination_offset, - std::string label) { + std::string_view label) { auto command = std::make_unique<BlitCopyTextureToBufferCommandGLES>(); command->label = label; command->source = std::move(source); @@ -131,7 +131,7 @@ BufferView source, std::shared_ptr<Texture> destination, IRect destination_region, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read) { @@ -150,7 +150,7 @@ // |BlitPass| bool BlitPassGLES::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture, - std::string label) { + std::string_view label) { auto command = std::make_unique<BlitGenerateMipmapCommandGLES>(); command->label = label; command->texture = std::move(texture);
diff --git a/impeller/renderer/backend/gles/blit_pass_gles.h b/impeller/renderer/backend/gles/blit_pass_gles.h index f6ad24e..321bd42 100644 --- a/impeller/renderer/backend/gles/blit_pass_gles.h +++ b/impeller/renderer/backend/gles/blit_pass_gles.h
@@ -35,7 +35,7 @@ bool IsValid() const override; // |BlitPass| - void OnSetLabel(std::string label) override; + void OnSetLabel(std::string_view label) override; // |BlitPass| bool EncodeCommands( @@ -50,27 +50,27 @@ std::shared_ptr<Texture> destination, IRect source_region, IPoint destination_origin, - std::string label) override; + std::string_view label) override; // |BlitPass| bool OnCopyTextureToBufferCommand(std::shared_ptr<Texture> source, std::shared_ptr<DeviceBuffer> destination, IRect source_region, size_t destination_offset, - std::string label) override; + std::string_view label) override; // |BlitPass| bool OnCopyBufferToTextureCommand(BufferView source, std::shared_ptr<Texture> destination, IRect destination_region, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read) override; // |BlitPass| bool OnGenerateMipmapCommand(std::shared_ptr<Texture> texture, - std::string label) override; + std::string_view label) override; BlitPassGLES(const BlitPassGLES&) = delete;
diff --git a/impeller/renderer/backend/gles/command_buffer_gles.cc b/impeller/renderer/backend/gles/command_buffer_gles.cc index ea6a651..d570cbc 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.cc +++ b/impeller/renderer/backend/gles/command_buffer_gles.cc
@@ -19,7 +19,7 @@ CommandBufferGLES::~CommandBufferGLES() = default; // |CommandBuffer| -void CommandBufferGLES::SetLabel(const std::string& label) const { +void CommandBufferGLES::SetLabel(std::string_view label) const { // Cannot support. }
diff --git a/impeller/renderer/backend/gles/command_buffer_gles.h b/impeller/renderer/backend/gles/command_buffer_gles.h index fe45b92..2188ccd 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.h +++ b/impeller/renderer/backend/gles/command_buffer_gles.h
@@ -26,7 +26,7 @@ ReactorGLES::Ref reactor); // |CommandBuffer| - void SetLabel(const std::string& label) const override; + void SetLabel(std::string_view label) const override; // |CommandBuffer| bool IsValid() const override;
diff --git a/impeller/renderer/backend/gles/device_buffer_gles.cc b/impeller/renderer/backend/gles/device_buffer_gles.cc index 38c1e59..f4caaf5 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.cc +++ b/impeller/renderer/backend/gles/device_buffer_gles.cc
@@ -110,13 +110,15 @@ } // |DeviceBuffer| -bool DeviceBufferGLES::SetLabel(const std::string& label) { +bool DeviceBufferGLES::SetLabel(std::string_view label) { +#ifdef IMPELLER_DEBUG reactor_->SetDebugLabel(handle_, label); +#endif // IMPELLER_DEBUG return true; } // |DeviceBuffer| -bool DeviceBufferGLES::SetLabel(const std::string& label, Range range) { +bool DeviceBufferGLES::SetLabel(std::string_view label, Range range) { // Cannot support debug label on the range. Set the label for the entire // range. return SetLabel(label);
diff --git a/impeller/renderer/backend/gles/device_buffer_gles.h b/impeller/renderer/backend/gles/device_buffer_gles.h index db65d0c..a18e010 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.h +++ b/impeller/renderer/backend/gles/device_buffer_gles.h
@@ -56,10 +56,10 @@ size_t offset) override; // |DeviceBuffer| - bool SetLabel(const std::string& label) override; + bool SetLabel(std::string_view label) override; // |DeviceBuffer| - bool SetLabel(const std::string& label, Range range) override; + bool SetLabel(std::string_view label, Range range) override; DeviceBufferGLES(const DeviceBufferGLES&) = delete;
diff --git a/impeller/renderer/backend/gles/pipeline_library_gles.cc b/impeller/renderer/backend/gles/pipeline_library_gles.cc index 6583142..493aabd 100644 --- a/impeller/renderer/backend/gles/pipeline_library_gles.cc +++ b/impeller/renderer/backend/gles/pipeline_library_gles.cc
@@ -48,7 +48,7 @@ static void LogShaderCompilationFailure(const ProcTableGLES& gl, GLuint shader, - const std::string& name, + std::string_view name, const fml::Mapping& source_mapping, ShaderStage stage) { std::stringstream stream; @@ -99,10 +99,9 @@ } gl.SetDebugLabel(DebugResourceType::kShader, vert_shader, - SPrintF("%s Vertex Shader", descriptor.GetLabel().c_str())); - gl.SetDebugLabel( - DebugResourceType::kShader, frag_shader, - SPrintF("%s Fragment Shader", descriptor.GetLabel().c_str())); + SPrintF("%s Vertex Shader", descriptor.GetLabel().data())); + gl.SetDebugLabel(DebugResourceType::kShader, frag_shader, + SPrintF("%s Fragment Shader", descriptor.GetLabel().data())); fml::ScopedCleanupClosure delete_vert_shader( [&gl, vert_shader]() { gl.DeleteShader(vert_shader); });
diff --git a/impeller/renderer/backend/gles/reactor_gles.cc b/impeller/renderer/backend/gles/reactor_gles.cc index 54e58ff..d8b7cb6 100644 --- a/impeller/renderer/backend/gles/reactor_gles.cc +++ b/impeller/renderer/backend/gles/reactor_gles.cc
@@ -275,7 +275,8 @@ } } -void ReactorGLES::SetDebugLabel(const HandleGLES& handle, std::string label) { +void ReactorGLES::SetDebugLabel(const HandleGLES& handle, + std::string_view label) { if (!can_set_debug_labels_) { return; } @@ -284,7 +285,7 @@ } WriterLock handles_lock(handles_mutex_); if (auto found = handles_.find(handle); found != handles_.end()) { - found->second.pending_debug_label = std::move(label); + found->second.pending_debug_label = label; } }
diff --git a/impeller/renderer/backend/gles/reactor_gles.h b/impeller/renderer/backend/gles/reactor_gles.h index b427c3f..a2e3ce6 100644 --- a/impeller/renderer/backend/gles/reactor_gles.h +++ b/impeller/renderer/backend/gles/reactor_gles.h
@@ -190,7 +190,7 @@ /// @param[in] handle The handle /// @param[in] label The label /// - void SetDebugLabel(const HandleGLES& handle, std::string label); + void SetDebugLabel(const HandleGLES& handle, std::string_view label); using Operation = std::function<void(const ReactorGLES& reactor)>;
diff --git a/impeller/renderer/backend/gles/render_pass_gles.cc b/impeller/renderer/backend/gles/render_pass_gles.cc index 54d8441..3906329 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/impeller/renderer/backend/gles/render_pass_gles.cc
@@ -36,8 +36,8 @@ } // |RenderPass| -void RenderPassGLES::OnSetLabel(std::string label) { - label_ = std::move(label); +void RenderPassGLES::OnSetLabel(std::string_view label) { + label_ = label; } void ConfigureBlending(const ProcTableGLES& gl,
diff --git a/impeller/renderer/backend/gles/render_pass_gles.h b/impeller/renderer/backend/gles/render_pass_gles.h index 9d4f986..e753a75 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.h +++ b/impeller/renderer/backend/gles/render_pass_gles.h
@@ -34,7 +34,7 @@ bool IsValid() const override; // |RenderPass| - void OnSetLabel(std::string label) override; + void OnSetLabel(std::string_view label) override; // |RenderPass| bool OnEncodeCommands(const Context& context) const override;
diff --git a/impeller/renderer/backend/metal/blit_pass_mtl.h b/impeller/renderer/backend/metal/blit_pass_mtl.h index fed45cb..7883819 100644 --- a/impeller/renderer/backend/metal/blit_pass_mtl.h +++ b/impeller/renderer/backend/metal/blit_pass_mtl.h
@@ -35,7 +35,7 @@ bool IsValid() const override; // |BlitPass| - void OnSetLabel(std::string label) override; + void OnSetLabel(std::string_view label) override; // |BlitPass| bool EncodeCommands( @@ -50,26 +50,26 @@ std::shared_ptr<Texture> destination, IRect source_region, IPoint destination_origin, - std::string label) override; + std::string_view label) override; // |BlitPass| bool OnCopyTextureToBufferCommand(std::shared_ptr<Texture> source, std::shared_ptr<DeviceBuffer> destination, IRect source_region, size_t destination_offset, - std::string label) override; + std::string_view label) override; // |BlitPass| bool OnCopyBufferToTextureCommand(BufferView source, std::shared_ptr<Texture> destination, IRect destination_region, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read) override; // |BlitPass| bool OnGenerateMipmapCommand(std::shared_ptr<Texture> texture, - std::string label) override; + std::string_view label) override; BlitPassMTL(const BlitPassMTL&) = delete;
diff --git a/impeller/renderer/backend/metal/blit_pass_mtl.mm b/impeller/renderer/backend/metal/blit_pass_mtl.mm index d1b583b..09f381f 100644 --- a/impeller/renderer/backend/metal/blit_pass_mtl.mm +++ b/impeller/renderer/backend/metal/blit_pass_mtl.mm
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "impeller/renderer/backend/metal/blit_pass_mtl.h" + #include <Metal/Metal.h> #import <MetalPerformanceShaders/MetalPerformanceShaders.h> #include <cstdint> @@ -50,11 +51,11 @@ return is_valid_; } -void BlitPassMTL::OnSetLabel(std::string label) { +void BlitPassMTL::OnSetLabel(std::string_view label) { if (label.empty()) { return; } - [encoder_ setLabel:@(label.c_str())]; + [encoder_ setLabel:@(label.data())]; } bool BlitPassMTL::EncodeCommands( @@ -70,7 +71,7 @@ std::shared_ptr<Texture> destination, IRect source_region, IPoint destination_origin, - std::string label) { + std::string_view label) { auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture(); if (!source_mtl) { return false; @@ -90,7 +91,7 @@ #ifdef IMPELLER_DEBUG if (is_metal_trace_active_) { - [encoder_ pushDebugGroup:@(label.c_str())]; + [encoder_ pushDebugGroup:@(label.data())]; } #endif // IMPELLER_DEBUG [encoder_ copyFromTexture:source_mtl @@ -139,7 +140,7 @@ std::shared_ptr<DeviceBuffer> destination, IRect source_region, size_t destination_offset, - std::string label) { + std::string_view label) { auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture(); if (!source_mtl) { return false; @@ -164,7 +165,7 @@ #ifdef IMPELLER_DEBUG if (is_metal_trace_active_) { - [encoder_ pushDebugGroup:@(label.c_str())]; + [encoder_ pushDebugGroup:@(label.data())]; } #endif // IMPELLER_DEBUG [encoder_ copyFromTexture:source_mtl @@ -189,7 +190,7 @@ BufferView source, std::shared_ptr<Texture> destination, IRect destination_region, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read) { @@ -215,7 +216,7 @@ #ifdef IMPELLER_DEBUG if (is_metal_trace_active_) { - [encoder_ pushDebugGroup:@(label.c_str())]; + [encoder_ pushDebugGroup:@(label.data())]; } #endif // IMPELLER_DEBUG [encoder_ @@ -241,10 +242,10 @@ // |BlitPass| bool BlitPassMTL::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture, - std::string label) { + std::string_view label) { #ifdef IMPELLER_DEBUG if (is_metal_trace_active_) { - [encoder_ pushDebugGroup:@(label.c_str())]; + [encoder_ pushDebugGroup:@(label.data())]; } #endif // IMPELLER_DEBUG auto result = TextureMTL::Cast(*texture).GenerateMipmap(encoder_);
diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.h b/impeller/renderer/backend/metal/command_buffer_mtl.h index dad6379..6c5c948 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.h +++ b/impeller/renderer/backend/metal/command_buffer_mtl.h
@@ -28,7 +28,7 @@ id<MTLCommandQueue> queue); // |CommandBuffer| - void SetLabel(const std::string& label) const override; + void SetLabel(std::string_view label) const override; // |CommandBuffer| bool IsValid() const override;
diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.mm b/impeller/renderer/backend/metal/command_buffer_mtl.mm index 21e9873..93bee9c 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/command_buffer_mtl.mm
@@ -140,12 +140,14 @@ return buffer_ != nil; } -void CommandBufferMTL::SetLabel(const std::string& label) const { +void CommandBufferMTL::SetLabel(std::string_view label) const { +#ifdef IMPELLER_DEBUG if (label.empty()) { return; } [buffer_ setLabel:@(label.data())]; +#endif // IMPELLER_DEBUG } static CommandBuffer::Status ToCommitResult(MTLCommandBufferStatus status) {
diff --git a/impeller/renderer/backend/metal/device_buffer_mtl.h b/impeller/renderer/backend/metal/device_buffer_mtl.h index 6980669..dbc61e2 100644 --- a/impeller/renderer/backend/metal/device_buffer_mtl.h +++ b/impeller/renderer/backend/metal/device_buffer_mtl.h
@@ -42,10 +42,10 @@ size_t offset) override; // |DeviceBuffer| - bool SetLabel(const std::string& label) override; + bool SetLabel(std::string_view label) override; // |DeviceBuffer| - bool SetLabel(const std::string& label, Range range) override; + bool SetLabel(std::string_view label, Range range) override; // |DeviceBuffer| void Flush(std::optional<Range> range) const override;
diff --git a/impeller/renderer/backend/metal/device_buffer_mtl.mm b/impeller/renderer/backend/metal/device_buffer_mtl.mm index ff763f2..4d0e053 100644 --- a/impeller/renderer/backend/metal/device_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/device_buffer_mtl.mm
@@ -64,20 +64,24 @@ #endif } -bool DeviceBufferMTL::SetLabel(const std::string& label) { +bool DeviceBufferMTL::SetLabel(std::string_view label) { +#ifdef IMPELLER_DEBUG if (label.empty()) { return false; } - [buffer_ setLabel:@(label.c_str())]; + [buffer_ setLabel:@(label.data())]; +#endif // IMPELLER_DEBUG return true; } -bool DeviceBufferMTL::SetLabel(const std::string& label, Range range) { +bool DeviceBufferMTL::SetLabel(std::string_view label, Range range) { +#ifdef IMPELLER_DEBUG if (label.empty()) { return false; } - [buffer_ addDebugMarker:@(label.c_str()) + [buffer_ addDebugMarker:@(label.data()) range:NSMakeRange(range.offset, range.length)]; +#endif // IMPELLER_DEBUG return true; }
diff --git a/impeller/renderer/backend/metal/pipeline_library_mtl.mm b/impeller/renderer/backend/metal/pipeline_library_mtl.mm index 5f0dbd4..6c157d1 100644 --- a/impeller/renderer/backend/metal/pipeline_library_mtl.mm +++ b/impeller/renderer/backend/metal/pipeline_library_mtl.mm
@@ -28,7 +28,7 @@ static void GetMTLRenderPipelineDescriptor(const PipelineDescriptor& desc, const Callback& callback) { auto descriptor = [[MTLRenderPipelineDescriptor alloc] init]; - descriptor.label = @(desc.GetLabel().c_str()); + descriptor.label = @(desc.GetLabel().data()); descriptor.rasterSampleCount = static_cast<NSUInteger>(desc.GetSampleCount()); bool created_specialized_function = false;
diff --git a/impeller/renderer/backend/metal/render_pass_mtl.h b/impeller/renderer/backend/metal/render_pass_mtl.h index 60cfe52..86f5a3c 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.h +++ b/impeller/renderer/backend/metal/render_pass_mtl.h
@@ -55,7 +55,7 @@ bool IsValid() const override; // |RenderPass| - void OnSetLabel(std::string label) override; + void OnSetLabel(std::string_view label) override; // |RenderPass| bool OnEncodeCommands(const Context& context) const override;
diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 3c9fda4..b03ae56 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm
@@ -170,7 +170,7 @@ return is_valid_; } -void RenderPassMTL::OnSetLabel(std::string label) { +void RenderPassMTL::OnSetLabel(std::string_view label) { #ifdef IMPELLER_DEBUG if (label.empty()) { return;
diff --git a/impeller/renderer/backend/vulkan/blit_pass_vk.cc b/impeller/renderer/backend/vulkan/blit_pass_vk.cc index 5c4aaba..5a3b2ef 100644 --- a/impeller/renderer/backend/vulkan/blit_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_pass_vk.cc
@@ -49,12 +49,7 @@ BlitPassVK::~BlitPassVK() = default; -void BlitPassVK::OnSetLabel(std::string label) { - if (label.empty()) { - return; - } - label_ = std::move(label); -} +void BlitPassVK::OnSetLabel(std::string_view label) {} // |BlitPass| bool BlitPassVK::IsValid() const { @@ -73,7 +68,7 @@ std::shared_ptr<Texture> destination, IRect source_region, IPoint destination_origin, - std::string label) { + std::string_view label) { const auto& cmd_buffer = command_buffer_->GetCommandBuffer(); const auto& src = TextureVK::Cast(*source); @@ -156,7 +151,7 @@ std::shared_ptr<DeviceBuffer> destination, IRect source_region, size_t destination_offset, - std::string label) { + std::string_view label) { const auto& cmd_buffer = command_buffer_->GetCommandBuffer(); // cast source and destination to TextureVK @@ -245,7 +240,7 @@ BufferView source, std::shared_ptr<Texture> destination, IRect destination_region, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read) { @@ -401,7 +396,7 @@ // |BlitPass| bool BlitPassVK::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture, - std::string label) { + std::string_view label) { auto& src = TextureVK::Cast(*texture); const auto size = src.GetTextureDescriptor().size;
diff --git a/impeller/renderer/backend/vulkan/blit_pass_vk.h b/impeller/renderer/backend/vulkan/blit_pass_vk.h index 625693b..073d422 100644 --- a/impeller/renderer/backend/vulkan/blit_pass_vk.h +++ b/impeller/renderer/backend/vulkan/blit_pass_vk.h
@@ -23,7 +23,6 @@ friend class CommandBufferVK; std::shared_ptr<CommandBufferVK> command_buffer_; - std::string label_; explicit BlitPassVK(std::shared_ptr<CommandBufferVK> command_buffer); @@ -31,7 +30,7 @@ bool IsValid() const override; // |BlitPass| - void OnSetLabel(std::string label) override; + void OnSetLabel(std::string_view label) override; // |BlitPass| bool EncodeCommands( @@ -50,26 +49,26 @@ std::shared_ptr<Texture> destination, IRect source_region, IPoint destination_origin, - std::string label) override; + std::string_view label) override; // |BlitPass| bool OnCopyTextureToBufferCommand(std::shared_ptr<Texture> source, std::shared_ptr<DeviceBuffer> destination, IRect source_region, size_t destination_offset, - std::string label) override; + std::string_view label) override; // |BlitPass| bool OnCopyBufferToTextureCommand(BufferView source, std::shared_ptr<Texture> destination, IRect destination_region, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read) override; // |BlitPass| bool OnGenerateMipmapCommand(std::shared_ptr<Texture> texture, - std::string label) override; + std::string_view label) override; BlitPassVK(const BlitPassVK&) = delete;
diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/impeller/renderer/backend/vulkan/command_buffer_vk.cc index 1e58aff..abe4971 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.cc
@@ -31,12 +31,14 @@ CommandBufferVK::~CommandBufferVK() = default; -void CommandBufferVK::SetLabel(const std::string& label) const { +void CommandBufferVK::SetLabel(std::string_view label) const { +#ifdef IMPELLER_DEBUG auto context = context_.lock(); if (!context) { return; } ContextVK::Cast(*context).SetDebugName(GetCommandBuffer(), label); +#endif // IMPELLER_DEBUG } bool CommandBufferVK::IsValid() const {
diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.h b/impeller/renderer/backend/vulkan/command_buffer_vk.h index b03635a..6a78787 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.h
@@ -95,7 +95,7 @@ std::shared_ptr<FenceWaiterVK> fence_waiter); // |CommandBuffer| - void SetLabel(const std::string& label) const override; + void SetLabel(std::string_view label) const override; // |CommandBuffer| bool IsValid() const override;
diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.cc b/impeller/renderer/backend/vulkan/device_buffer_vk.cc index a43a582..5e135a3 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.cc
@@ -48,7 +48,8 @@ return true; } -bool DeviceBufferVK::SetLabel(const std::string& label) { +bool DeviceBufferVK::SetLabel(std::string_view label) { +#ifdef IMPELLER_DEBUG auto context = context_.lock(); if (!context || !resource_->buffer.is_valid()) { // The context could have died at this point. @@ -57,11 +58,14 @@ ::vmaSetAllocationName(resource_->buffer.get().allocator, // resource_->buffer.get().allocation, // - label.c_str() // + label.data() // ); return ContextVK::Cast(*context).SetDebugName(resource_->buffer.get().buffer, label); +#else + return true; +#endif // IMPELLER_DEBUG } void DeviceBufferVK::Flush(std::optional<Range> range) const { @@ -78,7 +82,7 @@ flush_range.offset, flush_range.length); } -bool DeviceBufferVK::SetLabel(const std::string& label, Range range) { +bool DeviceBufferVK::SetLabel(std::string_view label, Range range) { // We do not have the ability to name ranges. Just name the whole thing. return SetLabel(label); }
diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.h b/impeller/renderer/backend/vulkan/device_buffer_vk.h index 744453d..540c165 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.h
@@ -61,10 +61,10 @@ size_t offset) override; // |DeviceBuffer| - bool SetLabel(const std::string& label) override; + bool SetLabel(std::string_view label) override; // |DeviceBuffer| - bool SetLabel(const std::string& label, Range range) override; + bool SetLabel(std::string_view label, Range range) override; // |DeviceBuffer| void Flush(std::optional<Range> range) const override;
diff --git a/impeller/renderer/backend/vulkan/pipeline_vk.cc b/impeller/renderer/backend/vulkan/pipeline_vk.cc index 727a60b..fba6034 100644 --- a/impeller/renderer/backend/vulkan/pipeline_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_vk.cc
@@ -7,6 +7,7 @@ #include "flutter/fml/make_copyable.h" #include "flutter/fml/status_or.h" #include "flutter/fml/trace_event.h" +#include "impeller/base/strings.h" #include "impeller/base/timing.h" #include "impeller/renderer/backend/vulkan/capabilities_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" @@ -159,8 +160,11 @@ return {}; } - ContextVK::SetDebugName(device, pass.get(), - "Compat Render Pass: " + desc.GetLabel()); +#ifdef IMPELLER_DEBUG + ContextVK::SetDebugName( + device, pass.get(), + SPrintF("Compat Render Pass: %s", desc.GetLabel().data())); +#endif // IMPELLER_DEBUG return pass; } @@ -207,8 +211,11 @@ "unable to create uniform descriptors")}; } - ContextVK::SetDebugName(device_holder->GetDevice(), descs_layout.get(), - "Descriptor Set Layout " + desc.GetLabel()); +#ifdef IMPELLER_DEBUG + ContextVK::SetDebugName( + device_holder->GetDevice(), descs_layout.get(), + SPrintF("Descriptor Set Layout: %s", desc.GetLabel().data())); +#endif // IMPELLER_DEBUG return fml::StatusOr<vk::UniqueDescriptorSetLayout>(std::move(descs_layout)); } @@ -229,8 +236,11 @@ "Could not create pipeline layout for pipeline.")}; } - ContextVK::SetDebugName(device_holder->GetDevice(), *pipeline_layout.value, - "Pipeline Layout " + desc.GetLabel()); +#ifdef IMPELLER_DEBUG + ContextVK::SetDebugName( + device_holder->GetDevice(), *pipeline_layout.value, + SPrintF("Pipeline Layout %s", desc.GetLabel().data())); +#endif // IMPELLER_DEBUG return std::move(pipeline_layout.value); } @@ -439,8 +449,10 @@ ReportPipelineCreationFeedback(desc, feedback); } +#ifdef IMPELLER_DEBUG ContextVK::SetDebugName(device_holder->GetDevice(), *pipeline, - "Pipeline " + desc.GetLabel()); + SPrintF("Pipeline %s", desc.GetLabel().data())); +#endif // IMPELLER_DEBUG return std::move(pipeline); } @@ -451,8 +463,7 @@ const std::shared_ptr<DeviceHolderVK>& device_holder, const std::weak_ptr<PipelineLibrary>& weak_library, std::shared_ptr<SamplerVK> immutable_sampler) { - TRACE_EVENT1("flutter", "PipelineVK::Create", "Name", - desc.GetLabel().c_str()); + TRACE_EVENT1("flutter", "PipelineVK::Create", "Name", desc.GetLabel().data()); auto library = weak_library.lock();
diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index df6d27d..ddf15f5 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc
@@ -238,10 +238,9 @@ return is_valid_; } -void RenderPassVK::OnSetLabel(std::string label) { +void RenderPassVK::OnSetLabel(std::string_view label) { #ifdef IMPELLER_DEBUG - ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), - std::string(label).c_str()); + ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), label.data()); #endif // IMPELLER_DEBUG }
diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index fa59713..034f888 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h
@@ -123,7 +123,7 @@ bool IsValid() const override; // |RenderPass| - void OnSetLabel(std::string label) override; + void OnSetLabel(std::string_view label) override; // |RenderPass| bool OnEncodeCommands(const Context& context) const override;
diff --git a/impeller/renderer/blit_pass.cc b/impeller/renderer/blit_pass.cc index 2c8d3c4..7d199d3 100644 --- a/impeller/renderer/blit_pass.cc +++ b/impeller/renderer/blit_pass.cc
@@ -16,18 +16,18 @@ BlitPass::~BlitPass() = default; -void BlitPass::SetLabel(std::string label) { +void BlitPass::SetLabel(std::string_view label) { if (label.empty()) { return; } - OnSetLabel(std::move(label)); + OnSetLabel(label); } bool BlitPass::AddCopy(std::shared_ptr<Texture> source, std::shared_ptr<Texture> destination, std::optional<IRect> source_region, IPoint destination_origin, - std::string label) { + std::string_view label) { if (!source) { VALIDATION_LOG << "Attempted to add a texture blit with no source."; return false; @@ -77,14 +77,14 @@ return OnCopyTextureToTextureCommand( std::move(source), std::move(destination), source_region.value(), - destination_origin, std::move(label)); + destination_origin, label); } bool BlitPass::AddCopy(std::shared_ptr<Texture> source, std::shared_ptr<DeviceBuffer> destination, std::optional<IRect> source_region, size_t destination_offset, - std::string label) { + std::string_view label) { if (!source) { VALIDATION_LOG << "Attempted to add a texture blit with no source."; return false; @@ -117,13 +117,13 @@ return OnCopyTextureToBufferCommand(std::move(source), std::move(destination), source_region.value(), destination_offset, - std::move(label)); + label); } bool BlitPass::AddCopy(BufferView source, std::shared_ptr<Texture> destination, std::optional<IRect> destination_region, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read) { @@ -162,9 +162,9 @@ return false; } - return OnCopyBufferToTextureCommand( - std::move(source), std::move(destination), destination_region_value, - std::move(label), mip_level, slice, convert_to_read); + return OnCopyBufferToTextureCommand(std::move(source), std::move(destination), + destination_region_value, label, + mip_level, slice, convert_to_read); } bool BlitPass::ConvertTextureToShaderRead( @@ -173,14 +173,14 @@ } bool BlitPass::GenerateMipmap(std::shared_ptr<Texture> texture, - std::string label) { + std::string_view label) { if (!texture) { VALIDATION_LOG << "Attempted to add an invalid mipmap generation command " "with no texture."; return false; } - return OnGenerateMipmapCommand(std::move(texture), std::move(label)); + return OnGenerateMipmapCommand(std::move(texture), label); } } // namespace impeller
diff --git a/impeller/renderer/blit_pass.h b/impeller/renderer/blit_pass.h index 5c3b8af..761a402 100644 --- a/impeller/renderer/blit_pass.h +++ b/impeller/renderer/blit_pass.h
@@ -30,7 +30,7 @@ virtual bool IsValid() const = 0; - void SetLabel(std::string label); + void SetLabel(std::string_view label); //---------------------------------------------------------------------------- /// @brief If the texture is not already in a shader read internal @@ -71,7 +71,7 @@ std::shared_ptr<Texture> destination, std::optional<IRect> source_region = std::nullopt, IPoint destination_origin = {}, - std::string label = ""); + std::string_view label = ""); //---------------------------------------------------------------------------- /// @brief Record a command to copy the contents of a texture to a @@ -94,7 +94,7 @@ std::shared_ptr<DeviceBuffer> destination, std::optional<IRect> source_region = std::nullopt, size_t destination_offset = 0, - std::string label = ""); + std::string_view label = ""); //---------------------------------------------------------------------------- /// @brief Record a command to copy the contents of a buffer to a @@ -127,7 +127,7 @@ bool AddCopy(BufferView source, std::shared_ptr<Texture> destination, std::optional<IRect> destination_region = std::nullopt, - std::string label = "", + std::string_view label = "", uint32_t mip_level = 0, uint32_t slice = 0, bool convert_to_read = true); @@ -140,7 +140,8 @@ /// /// @return If the command was valid for subsequent commitment. /// - bool GenerateMipmap(std::shared_ptr<Texture> texture, std::string label = ""); + bool GenerateMipmap(std::shared_ptr<Texture> texture, + std::string_view label = ""); //---------------------------------------------------------------------------- /// @brief Encode the recorded commands to the underlying command buffer. @@ -156,33 +157,33 @@ protected: explicit BlitPass(); - virtual void OnSetLabel(std::string label) = 0; + virtual void OnSetLabel(std::string_view label) = 0; virtual bool OnCopyTextureToTextureCommand( std::shared_ptr<Texture> source, std::shared_ptr<Texture> destination, IRect source_region, IPoint destination_origin, - std::string label) = 0; + std::string_view label) = 0; virtual bool OnCopyTextureToBufferCommand( std::shared_ptr<Texture> source, std::shared_ptr<DeviceBuffer> destination, IRect source_region, size_t destination_offset, - std::string label) = 0; + std::string_view label) = 0; virtual bool OnCopyBufferToTextureCommand( BufferView source, std::shared_ptr<Texture> destination, IRect destination_region, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read) = 0; virtual bool OnGenerateMipmapCommand(std::shared_ptr<Texture> texture, - std::string label) = 0; + std::string_view label) = 0; private: BlitPass(const BlitPass&) = delete;
diff --git a/impeller/renderer/command_buffer.h b/impeller/renderer/command_buffer.h index 4794941..958b4d0 100644 --- a/impeller/renderer/command_buffer.h +++ b/impeller/renderer/command_buffer.h
@@ -58,7 +58,7 @@ virtual bool IsValid() const = 0; - virtual void SetLabel(const std::string& label) const = 0; + virtual void SetLabel(std::string_view label) const = 0; //---------------------------------------------------------------------------- /// @brief Force execution of pending GPU commands.
diff --git a/impeller/renderer/compute_pipeline_descriptor.cc b/impeller/renderer/compute_pipeline_descriptor.cc index efb9cda..801eaee 100644 --- a/impeller/renderer/compute_pipeline_descriptor.cc +++ b/impeller/renderer/compute_pipeline_descriptor.cc
@@ -33,8 +33,8 @@ } ComputePipelineDescriptor& ComputePipelineDescriptor::SetLabel( - std::string label) { - label_ = std::move(label); + std::string_view label) { + label_ = label; return *this; }
diff --git a/impeller/renderer/compute_pipeline_descriptor.h b/impeller/renderer/compute_pipeline_descriptor.h index 85311fe..112894b 100644 --- a/impeller/renderer/compute_pipeline_descriptor.h +++ b/impeller/renderer/compute_pipeline_descriptor.h
@@ -24,7 +24,7 @@ ~ComputePipelineDescriptor(); - ComputePipelineDescriptor& SetLabel(std::string label); + ComputePipelineDescriptor& SetLabel(std::string_view label); const std::string& GetLabel() const;
diff --git a/impeller/renderer/pipeline_descriptor.cc b/impeller/renderer/pipeline_descriptor.cc index 9ae6710..0e6243e 100644 --- a/impeller/renderer/pipeline_descriptor.cc +++ b/impeller/renderer/pipeline_descriptor.cc
@@ -68,8 +68,8 @@ specialization_constants_ == other.specialization_constants_; } -PipelineDescriptor& PipelineDescriptor::SetLabel(std::string label) { - label_ = std::move(label); +PipelineDescriptor& PipelineDescriptor::SetLabel(std::string_view label) { + label_ = std::string(label); return *this; } @@ -231,7 +231,7 @@ return nullptr; } -const std::string& PipelineDescriptor::GetLabel() const { +std::string_view PipelineDescriptor::GetLabel() const { return label_; }
diff --git a/impeller/renderer/pipeline_descriptor.h b/impeller/renderer/pipeline_descriptor.h index 3ea2ae6..83eb56f 100644 --- a/impeller/renderer/pipeline_descriptor.h +++ b/impeller/renderer/pipeline_descriptor.h
@@ -27,9 +27,9 @@ ~PipelineDescriptor(); - PipelineDescriptor& SetLabel(std::string label); + PipelineDescriptor& SetLabel(std::string_view label); - const std::string& GetLabel() const; + std::string_view GetLabel() const; PipelineDescriptor& SetSampleCount(SampleCount samples);
diff --git a/impeller/renderer/render_pass.cc b/impeller/renderer/render_pass.cc index df68c49..a0c6e56 100644 --- a/impeller/renderer/render_pass.cc +++ b/impeller/renderer/render_pass.cc
@@ -50,11 +50,11 @@ return orthographic_; } -void RenderPass::SetLabel(std::string label) { +void RenderPass::SetLabel(std::string_view label) { if (label.empty()) { return; } - OnSetLabel(std::move(label)); + OnSetLabel(label); } bool RenderPass::AddCommand(Command&& command) {
diff --git a/impeller/renderer/render_pass.h b/impeller/renderer/render_pass.h index c0e9b73..9d83ed1 100644 --- a/impeller/renderer/render_pass.h +++ b/impeller/renderer/render_pass.h
@@ -6,7 +6,6 @@ #define FLUTTER_IMPELLER_RENDERER_RENDER_PASS_H_ #include <cstddef> -#include <string> #include "fml/status.h" #include "impeller/core/formats.h" @@ -45,7 +44,7 @@ virtual bool IsValid() const = 0; - void SetLabel(std::string label); + void SetLabel(std::string_view label); /// @brief Reserve [command_count] commands in the HAL command buffer. /// @@ -269,7 +268,7 @@ static bool ValidateIndexBuffer(const BufferView& index_buffer, IndexType index_type); - virtual void OnSetLabel(std::string label) = 0; + virtual void OnSetLabel(std::string_view label) = 0; virtual bool OnEncodeCommands(const Context& context) const = 0;
diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index 6afa486..389ecd2 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc
@@ -260,7 +260,7 @@ const Context& context, ISize size, int mip_count, - const std::string& label, + std::string_view label, RenderTarget::AttachmentConfig color_attachment_config, std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config, const std::shared_ptr<Texture>& existing_color_texture, @@ -289,7 +289,9 @@ return {}; } } - color0_tex->SetLabel(SPrintF("%s Color Texture", label.c_str())); +#ifdef IMPELLER_DEBUG + color0_tex->SetLabel(SPrintF("%s Color Texture", label.data())); +#endif // IMPELLER_DEBUG ColorAttachment color0; color0.clear_color = color_attachment_config.clear_color; @@ -314,7 +316,7 @@ const Context& context, ISize size, int mip_count, - const std::string& label, + std::string_view label, RenderTarget::AttachmentConfigMSAA color_attachment_config, std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config, const std::shared_ptr<Texture>& existing_color_msaa_texture, @@ -349,8 +351,10 @@ return {}; } } +#ifdef IMPELLER_DEBUG color0_msaa_tex->SetLabel( - SPrintF("%s Color Texture (Multisample)", label.c_str())); + SPrintF("%s Color Texture (Multisample)", label.data())); +#endif // IMPELLER_DEBUG // Create color resolve texture. std::shared_ptr<Texture> color0_resolve_tex; @@ -372,7 +376,9 @@ return {}; } } - color0_resolve_tex->SetLabel(SPrintF("%s Color Texture", label.c_str())); +#ifdef IMPELLER_DEBUG + color0_resolve_tex->SetLabel(SPrintF("%s Color Texture", label.data())); +#endif // IMPELLER_DEBUG // Color attachment. @@ -415,7 +421,7 @@ Allocator& allocator, ISize size, bool msaa, - const std::string& label, + std::string_view label, RenderTarget::AttachmentConfig stencil_attachment_config, const std::shared_ptr<Texture>& existing_depth_stencil_texture) { std::shared_ptr<Texture> depth_stencil_texture; @@ -451,8 +457,9 @@ stencil0.clear_stencil = 0u; stencil0.texture = std::move(depth_stencil_texture); - stencil0.texture->SetLabel( - SPrintF("%s Depth+Stencil Texture", label.c_str())); +#ifdef IMPELLER_DEBUG + stencil0.texture->SetLabel(SPrintF("%s Depth+Stencil Texture", label.data())); +#endif // IMPELLER_DEBUG SetDepthAttachment(std::move(depth0)); SetStencilAttachment(std::move(stencil0)); }
diff --git a/impeller/renderer/render_target.h b/impeller/renderer/render_target.h index 6d63527..77f5bf4 100644 --- a/impeller/renderer/render_target.h +++ b/impeller/renderer/render_target.h
@@ -82,7 +82,7 @@ Allocator& allocator, ISize size, bool msaa, - const std::string& label = "Offscreen", + std::string_view label = "Offscreen", RenderTarget::AttachmentConfig stencil_attachment_config = RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr<Texture>& depth_stencil_texture = nullptr); @@ -149,7 +149,7 @@ const Context& context, ISize size, int mip_count, - const std::string& label = "Offscreen", + std::string_view label = "Offscreen", RenderTarget::AttachmentConfig color_attachment_config = RenderTarget::kDefaultColorAttachmentConfig, std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config = @@ -161,7 +161,7 @@ const Context& context, ISize size, int mip_count, - const std::string& label = "Offscreen MSAA", + std::string_view label = "Offscreen MSAA", RenderTarget::AttachmentConfigMSAA color_attachment_config = RenderTarget::kDefaultColorAttachmentConfigMSAA, std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config =
diff --git a/impeller/renderer/testing/mocks.h b/impeller/renderer/testing/mocks.h index cc781b8..1e02636 100644 --- a/impeller/renderer/testing/mocks.h +++ b/impeller/renderer/testing/mocks.h
@@ -28,11 +28,11 @@ explicit MockDeviceBuffer(const DeviceBufferDescriptor& desc) : DeviceBuffer(desc) {} - MOCK_METHOD(bool, SetLabel, (const std::string& label), (override)); + MOCK_METHOD(bool, SetLabel, (std::string_view label), (override)); MOCK_METHOD(bool, SetLabel, - (const std::string& label, Range range), + (std::string_view label, Range range), (override)); MOCK_METHOD(uint8_t*, OnGetContents, (), (const, override)); @@ -63,7 +63,7 @@ EncodeCommands, (const std::shared_ptr<Allocator>& transients_allocator), (const, override)); - MOCK_METHOD(void, OnSetLabel, (std::string label), (override)); + MOCK_METHOD(void, OnSetLabel, (std::string_view label), (override)); MOCK_METHOD(bool, ResizeTexture, @@ -77,7 +77,7 @@ std::shared_ptr<Texture> destination, IRect source_region, IPoint destination_origin, - std::string label), + std::string_view label), (override)); MOCK_METHOD(bool, @@ -86,21 +86,21 @@ std::shared_ptr<DeviceBuffer> destination, IRect source_region, size_t destination_offset, - std::string label), + std::string_view label), (override)); MOCK_METHOD(bool, OnCopyBufferToTextureCommand, (BufferView source, std::shared_ptr<Texture> destination, IRect destination_rect, - std::string label, + std::string_view label, uint32_t mip_level, uint32_t slice, bool convert_to_read), (override)); MOCK_METHOD(bool, OnGenerateMipmapCommand, - (std::shared_ptr<Texture> texture, std::string label), + (std::shared_ptr<Texture> texture, std::string_view label), (override)); }; @@ -114,7 +114,7 @@ OnEncodeCommands, (const Context& context), (const, override)); - MOCK_METHOD(void, OnSetLabel, (std::string label), (override)); + MOCK_METHOD(void, OnSetLabel, (std::string_view label), (override)); }; class MockCommandBuffer : public CommandBuffer { @@ -122,7 +122,7 @@ explicit MockCommandBuffer(std::weak_ptr<const Context> context) : CommandBuffer(std::move(context)) {} MOCK_METHOD(bool, IsValid, (), (const, override)); - MOCK_METHOD(void, SetLabel, (const std::string& label), (const, override)); + MOCK_METHOD(void, SetLabel, (std::string_view label), (const, override)); MOCK_METHOD(std::shared_ptr<BlitPass>, OnCreateBlitPass, (), (override)); MOCK_METHOD(bool, OnSubmitCommands,
diff --git a/impeller/toolkit/interop/impeller.cc b/impeller/toolkit/interop/impeller.cc index 1484eda..05d8c03 100644 --- a/impeller/toolkit/interop/impeller.cc +++ b/impeller/toolkit/interop/impeller.cc
@@ -1009,7 +1009,8 @@ IMPELLER_EXTERN_C ImpellerParagraphBuilder ImpellerParagraphBuilderNew( ImpellerTypographyContext context) { - auto builder = Create<ParagraphBuilder>(*GetPeer(context)); + auto builder = + Create<ParagraphBuilder>(Ref<TypographyContext>(GetPeer(context))); if (!builder->IsValid()) { VALIDATION_LOG << "Could not create valid paragraph builder."; return nullptr;
diff --git a/impeller/toolkit/interop/impeller_unittests.cc b/impeller/toolkit/interop/impeller_unittests.cc index c582944..2a4690e 100644 --- a/impeller/toolkit/interop/impeller_unittests.cc +++ b/impeller/toolkit/interop/impeller_unittests.cc
@@ -245,4 +245,97 @@ })); } +static void DrawTextFrame(ImpellerTypographyContext tc, + ImpellerDisplayListBuilder builder, + ImpellerParagraphStyle p_style, + ImpellerPaint bg, + ImpellerColor color, + ImpellerTextAlignment align, + float x_offset) { + const char text[] = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + + ImpellerPaint fg = ImpellerPaintNew(); + + // Draw a box. + ImpellerPaintSetColor(fg, &color); + ImpellerPaintSetDrawStyle(fg, kImpellerDrawStyleStroke); + ImpellerRect box_rect = {10 + x_offset, 10, 200, 200}; + ImpellerDisplayListBuilderDrawRect(builder, &box_rect, fg); + + // Draw text. + ImpellerPaintSetDrawStyle(fg, kImpellerDrawStyleFill); + ImpellerParagraphStyleSetForeground(p_style, fg); + ImpellerParagraphStyleSetBackground(p_style, bg); + ImpellerParagraphStyleSetTextAlignment(p_style, align); + ImpellerParagraphBuilder p_builder = ImpellerParagraphBuilderNew(tc); + ImpellerParagraphBuilderPushStyle(p_builder, p_style); + ImpellerParagraphBuilderAddText(p_builder, (const uint8_t*)text, + sizeof(text)); + ImpellerParagraph left_p = ImpellerParagraphBuilderBuildParagraphNew( + p_builder, box_rect.width - 20.0); + ImpellerPoint pt = {20.0f + x_offset, 20.0f}; + float w = ImpellerParagraphGetMaxWidth(left_p); + float h = ImpellerParagraphGetHeight(left_p); + ImpellerDisplayListBuilderDrawParagraph(builder, left_p, &pt); + ImpellerPaintSetDrawStyle(fg, kImpellerDrawStyleStroke); + + // Draw an inner box around the paragraph layout. + ImpellerRect inner_box_rect = {pt.x, pt.y, w, h}; + ImpellerDisplayListBuilderDrawRect(builder, &inner_box_rect, fg); + + ImpellerParagraphRelease(left_p); + ImpellerParagraphBuilderRelease(p_builder); + ImpellerPaintRelease(fg); +} + +TEST_P(InteropPlaygroundTest, CanRenderTextAlignments) { + ImpellerTypographyContext tc = ImpellerTypographyContextNew(); + + ImpellerDisplayList dl = NULL; + + { + ImpellerDisplayListBuilder builder = ImpellerDisplayListBuilderNew(NULL); + ImpellerPaint bg = ImpellerPaintNew(); + ImpellerParagraphStyle p_style = ImpellerParagraphStyleNew(); + ImpellerParagraphStyleSetFontFamily(p_style, "Roboto"); + ImpellerParagraphStyleSetFontSize(p_style, 24.0); + ImpellerParagraphStyleSetFontWeight(p_style, kImpellerFontWeight400); + + // Clear the background to a white color. + ImpellerColor clear_color = {1.0, 1.0, 1.0, 1.0}; + ImpellerPaintSetColor(bg, &clear_color); + ImpellerDisplayListBuilderDrawPaint(builder, bg); + + // Draw red, left-aligned text. + ImpellerColor red = {1.0, 0.0, 0.0, 1.0}; + DrawTextFrame(tc, builder, p_style, bg, red, kImpellerTextAlignmentLeft, + 0.0); + + // Draw green, centered text. + ImpellerColor green = {0.0, 1.0, 0.0, 1.0}; + DrawTextFrame(tc, builder, p_style, bg, green, kImpellerTextAlignmentCenter, + 220.0); + + // Draw blue, right-aligned text. + ImpellerColor blue = {0.0, 0.0, 1.0, 1.0}; + DrawTextFrame(tc, builder, p_style, bg, blue, kImpellerTextAlignmentRight, + 440.0); + + dl = ImpellerDisplayListBuilderCreateDisplayListNew(builder); + + ImpellerPaintRelease(bg); + ImpellerDisplayListBuilderRelease(builder); + } + + ASSERT_TRUE( + OpenPlaygroundHere([&](const auto& context, const auto& surface) -> bool { + ImpellerSurfaceDrawDisplayList(surface.GetC(), dl); + return true; + })); + + ImpellerDisplayListRelease(dl); + ImpellerTypographyContextRelease(tc); +} + } // namespace impeller::interop::testing
diff --git a/impeller/toolkit/interop/paragraph_builder.cc b/impeller/toolkit/interop/paragraph_builder.cc index 4997d59..d983c38 100644 --- a/impeller/toolkit/interop/paragraph_builder.cc +++ b/impeller/toolkit/interop/paragraph_builder.cc
@@ -10,41 +10,29 @@ namespace impeller::interop { -ParagraphBuilder::ParagraphBuilder(const TypographyContext& context) { - if (!context.IsValid()) { - VALIDATION_LOG << "Invalid typography context."; - return; - } - - static txt::ParagraphStyle kBaseStyle; - - builder_ = std::make_unique<txt::ParagraphBuilderSkia>( - kBaseStyle, // - context.GetFontCollection(), // - true // is impeller enabled - ); -} +ParagraphBuilder::ParagraphBuilder(ScopedObject<TypographyContext> context) + : context_(std::move(context)) {} ParagraphBuilder::~ParagraphBuilder() = default; bool ParagraphBuilder::IsValid() const { - return !!builder_; + return !!context_; } void ParagraphBuilder::PushStyle(const ParagraphStyle& style) { - builder_->PushStyle(style.CreateTextStyle()); + GetBuilder(style.GetParagraphStyle())->PushStyle(style.CreateTextStyle()); } void ParagraphBuilder::PopStyle() { - builder_->Pop(); + GetBuilder()->Pop(); } void ParagraphBuilder::AddText(const uint8_t* data, size_t byte_length) { - builder_->AddText(data, byte_length); + GetBuilder()->AddText(data, byte_length); } ScopedObject<Paragraph> ParagraphBuilder::Build(Scalar width) const { - auto txt_paragraph = builder_->Build(); + auto txt_paragraph = GetBuilder()->Build(); if (!txt_paragraph) { return nullptr; } @@ -52,4 +40,23 @@ return Create<Paragraph>(std::move(txt_paragraph)); } +const std::unique_ptr<txt::ParagraphBuilder>& ParagraphBuilder::GetBuilder( + const txt::ParagraphStyle& style) const { + if (lazy_builder_) { + return lazy_builder_; + } + lazy_builder_ = std::make_unique<txt::ParagraphBuilderSkia>( + style, // + context_->GetFontCollection(), // + true // is impeller enabled + ); + return lazy_builder_; +} + +const std::unique_ptr<txt::ParagraphBuilder>& ParagraphBuilder::GetBuilder() + const { + static txt::ParagraphStyle kDefaultStyle; + return GetBuilder(kDefaultStyle); +} + } // namespace impeller::interop
diff --git a/impeller/toolkit/interop/paragraph_builder.h b/impeller/toolkit/interop/paragraph_builder.h index 1560446..8ea141e 100644 --- a/impeller/toolkit/interop/paragraph_builder.h +++ b/impeller/toolkit/interop/paragraph_builder.h
@@ -20,7 +20,7 @@ : public Object<ParagraphBuilder, IMPELLER_INTERNAL_HANDLE_NAME(ImpellerParagraphBuilder)> { public: - explicit ParagraphBuilder(const TypographyContext& context); + explicit ParagraphBuilder(ScopedObject<TypographyContext> context); ~ParagraphBuilder() override; @@ -39,7 +39,13 @@ ScopedObject<Paragraph> Build(Scalar width) const; private: - std::unique_ptr<txt::ParagraphBuilder> builder_; + ScopedObject<TypographyContext> context_; + mutable std::unique_ptr<txt::ParagraphBuilder> lazy_builder_; + + const std::unique_ptr<txt::ParagraphBuilder>& GetBuilder( + const txt::ParagraphStyle& style) const; + + const std::unique_ptr<txt::ParagraphBuilder>& GetBuilder() const; }; } // namespace impeller::interop
diff --git a/impeller/toolkit/interop/paragraph_style.cc b/impeller/toolkit/interop/paragraph_style.cc index 14733dc..55a7fcd 100644 --- a/impeller/toolkit/interop/paragraph_style.cc +++ b/impeller/toolkit/interop/paragraph_style.cc
@@ -51,18 +51,23 @@ } void ParagraphStyle::SetBackground(ScopedObject<Paint> paint) { - backgrond_ = std::move(paint); + background_ = std::move(paint); } txt::TextStyle ParagraphStyle::CreateTextStyle() const { auto style = style_.GetTextStyle(); + if (foreground_) { style.foreground = foreground_->GetPaint(); } - if (backgrond_) { - style.background = backgrond_->GetPaint(); + if (background_) { + style.background = background_->GetPaint(); } return style; } +const txt::ParagraphStyle& ParagraphStyle::GetParagraphStyle() const { + return style_; +} + } // namespace impeller::interop
diff --git a/impeller/toolkit/interop/paragraph_style.h b/impeller/toolkit/interop/paragraph_style.h index 37165e3..0a3e898 100644 --- a/impeller/toolkit/interop/paragraph_style.h +++ b/impeller/toolkit/interop/paragraph_style.h
@@ -48,10 +48,12 @@ txt::TextStyle CreateTextStyle() const; + const txt::ParagraphStyle& GetParagraphStyle() const; + private: txt::ParagraphStyle style_; ScopedObject<Paint> foreground_; - ScopedObject<Paint> backgrond_; + ScopedObject<Paint> background_; }; } // namespace impeller::interop
diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index adb06b4..6a11189 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc
@@ -483,6 +483,9 @@ } texture->SetLabel(impeller::SPrintF("ui.Image(%p)", texture.get()).c_str()); + + context->DisposeThreadLocalCachedResources(); + return std::make_pair(impeller::DlImageImpeller::Make(std::move(texture)), std::string()); }
diff --git a/lib/ui/painting/image_decoder_no_gl_unittests.h b/lib/ui/painting/image_decoder_no_gl_unittests.h index b1839f0..4f4cdf2 100644 --- a/lib/ui/painting/image_decoder_no_gl_unittests.h +++ b/lib/ui/painting/image_decoder_no_gl_unittests.h
@@ -44,9 +44,9 @@ ~TestImpellerDeviceBuffer() { free(bytes_); } private: - bool SetLabel(const std::string& label) override { return true; } + bool SetLabel(std::string_view label) override { return true; } - bool SetLabel(const std::string& label, Range range) override { return true; } + bool SetLabel(std::string_view label, Range range) override { return true; } uint8_t* OnGetContents() const override { return bytes_; }
diff --git a/lib/ui/painting/image_decoder_unittests.cc b/lib/ui/painting/image_decoder_unittests.cc index d8f7667..69096ee 100644 --- a/lib/ui/painting/image_decoder_unittests.cc +++ b/lib/ui/painting/image_decoder_unittests.cc
@@ -92,8 +92,12 @@ tasks_.clear(); } + void DisposeThreadLocalCachedResources() override { did_dispose_ = true; } + void Shutdown() override {} + bool DidDisposeResources() const { return did_dispose_; } + mutable size_t command_buffer_count_ = 0; private: @@ -103,6 +107,7 @@ }; std::vector<PendingTask> tasks_; std::shared_ptr<const Capabilities> capabilities_; + bool did_dispose_ = false; }; } // namespace impeller @@ -367,12 +372,14 @@ EXPECT_EQ(no_gpu_access_context->command_buffer_count_, 0ul); EXPECT_FALSE(invoked); + EXPECT_EQ(no_gpu_access_context->DidDisposeResources(), false); auto result = ImageDecoderImpeller::UploadTextureToStorage( no_gpu_access_context, bitmap); ASSERT_EQ(no_gpu_access_context->command_buffer_count_, 0ul); ASSERT_EQ(result.second, ""); + EXPECT_EQ(no_gpu_access_context->DidDisposeResources(), true); no_gpu_access_context->FlushTasks(/*fail=*/true); }
diff --git a/lib/ui/window/pointer_data_packet_converter.cc b/lib/ui/window/pointer_data_packet_converter.cc index 45b05a0..b764028 100644 --- a/lib/ui/window/pointer_data_packet_converter.cc +++ b/lib/ui/window/pointer_data_packet_converter.cc
@@ -74,7 +74,45 @@ break; } case PointerData::Change::kAdd: { - FML_DCHECK(states_.find(pointer_data.device) == states_.end()); + auto iter = states_.find(pointer_data.device); + if (iter != states_.end()) { + // Synthesizes a remove event if the pointer was not previously + // removed. + PointerState state = iter->second; + PointerData synthesized_data = pointer_data; + synthesized_data.physical_x = state.physical_x; + synthesized_data.physical_y = state.physical_y; + synthesized_data.pan_x = state.pan_x; + synthesized_data.pan_y = state.pan_y; + synthesized_data.scale = state.scale; + synthesized_data.rotation = state.rotation; + synthesized_data.buttons = state.buttons; + synthesized_data.synthesized = 1; + + // The framework expects an add event to always follow a remove event, + // and remove events with invalid views are ignored. + // To meet the framework's expectations, the view ID of the add event + // is used for the remove event if the old view has been destroyed. + if (delegate_.ViewExists(state.view_id)) { + synthesized_data.view_id = state.view_id; + + if (state.is_down) { + // Synthesizes cancel event if the pointer is down. + PointerData synthesized_cancel_event = synthesized_data; + synthesized_cancel_event.change = PointerData::Change::kCancel; + UpdatePointerIdentifier(synthesized_cancel_event, state, false); + + state.is_down = false; + converted_pointers.push_back(synthesized_cancel_event); + } + } + + PointerData synthesized_remove_event = synthesized_data; + synthesized_remove_event.change = PointerData::Change::kRemove; + + converted_pointers.push_back(synthesized_remove_event); + } + EnsurePointerState(pointer_data); converted_pointers.push_back(pointer_data); break; @@ -84,6 +122,11 @@ auto iter = states_.find(pointer_data.device); FML_DCHECK(iter != states_.end()); PointerState state = iter->second; + if (state.view_id != pointer_data.view_id) { + // Ignores remove event if the pointer was previously added to a + // different view. + break; + } if (state.is_down) { // Synthesizes cancel event if the pointer is down. @@ -362,6 +405,7 @@ state.physical_y = pointer_data.physical_y; state.pan_x = 0; state.pan_y = 0; + state.view_id = pointer_data.view_id; states_[pointer_data.device] = state; return state; }
diff --git a/lib/ui/window/pointer_data_packet_converter.h b/lib/ui/window/pointer_data_packet_converter.h index 146ade2..7b1b823 100644 --- a/lib/ui/window/pointer_data_packet_converter.h +++ b/lib/ui/window/pointer_data_packet_converter.h
@@ -38,6 +38,7 @@ double scale; double rotation; int64_t buttons; + int64_t view_id; }; //------------------------------------------------------------------------------
diff --git a/lib/ui/window/pointer_data_packet_converter_unittests.cc b/lib/ui/window/pointer_data_packet_converter_unittests.cc index 4f6a37f..0eb9667 100644 --- a/lib/ui/window/pointer_data_packet_converter_unittests.cc +++ b/lib/ui/window/pointer_data_packet_converter_unittests.cc
@@ -510,6 +510,108 @@ ASSERT_EQ(result[3].buttons, 0); } +TEST(PointerDataPacketConverterTest, CanSynthesizeRemove) { + TestDelegate delegate; + delegate.AddView(100); + delegate.AddView(200); + PointerDataPacketConverter converter(delegate); + auto packet = std::make_unique<PointerDataPacket>(3); + + 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::kDown, 0, 3.0, 4.0, 1); + data.view_id = 100; + packet->SetPointerData(1, data); + CreateSimulatedPointerData(data, PointerData::Change::kAdd, 0, 0.0, 0.0, 0); + data.view_id = 200; + packet->SetPointerData(2, data); + auto converted_packet = converter.Convert(*packet); + + std::vector<PointerData> result; + UnpackPointerPacket(result, std::move(converted_packet)); + + ASSERT_EQ(result.size(), (size_t)6); + ASSERT_EQ(result[0].synthesized, 0); + ASSERT_EQ(result[0].view_id, 100); + + // A hover should be synthesized. + ASSERT_EQ(result[1].change, PointerData::Change::kHover); + ASSERT_EQ(result[1].synthesized, 1); + ASSERT_EQ(result[1].physical_delta_x, 3.0); + ASSERT_EQ(result[1].physical_delta_y, 4.0); + ASSERT_EQ(result[1].buttons, 0); + + ASSERT_EQ(result[2].change, PointerData::Change::kDown); + ASSERT_EQ(result[2].pointer_identifier, 1); + ASSERT_EQ(result[2].synthesized, 0); + ASSERT_EQ(result[2].buttons, 1); + + // A cancel should be synthesized. + ASSERT_EQ(result[3].change, PointerData::Change::kCancel); + ASSERT_EQ(result[3].pointer_identifier, 1); + ASSERT_EQ(result[3].synthesized, 1); + ASSERT_EQ(result[3].physical_x, 3.0); + ASSERT_EQ(result[3].physical_y, 4.0); + ASSERT_EQ(result[3].buttons, 1); + + // A remove should be synthesized. + ASSERT_EQ(result[4].physical_x, 3.0); + ASSERT_EQ(result[4].physical_y, 4.0); + ASSERT_EQ(result[4].synthesized, 1); + ASSERT_EQ(result[4].view_id, 100); + + ASSERT_EQ(result[5].synthesized, 0); + ASSERT_EQ(result[5].view_id, 200); +} + +TEST(PointerDataPacketConverterTest, + CanAvoidDoubleRemoveAfterSynthesizedRemove) { + TestDelegate delegate; + delegate.AddView(100); + delegate.AddView(200); + PointerDataPacketConverter converter(delegate); + auto packet = std::make_unique<PointerDataPacket>(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::kAdd, 0, 0.0, 0.0, 0); + data.view_id = 200; + packet->SetPointerData(1, data); + auto converted_packet = converter.Convert(*packet); + + std::vector<PointerData> result; + UnpackPointerPacket(result, std::move(converted_packet)); + + ASSERT_EQ(result.size(), (size_t)3); + ASSERT_EQ(result[0].synthesized, 0); + ASSERT_EQ(result[0].view_id, 100); + + // A remove should be synthesized. + ASSERT_EQ(result[1].synthesized, 1); + ASSERT_EQ(result[1].view_id, 100); + + ASSERT_EQ(result[2].synthesized, 0); + ASSERT_EQ(result[2].view_id, 200); + + // Simulate a double remove. + packet = std::make_unique<PointerDataPacket>(1); + CreateSimulatedPointerData(data, PointerData::Change::kRemove, 0, 0.0, 0.0, + 0); + data.view_id = 100; + packet->SetPointerData(0, data); + converted_packet = converter.Convert(*packet); + + result.clear(); + UnpackPointerPacket(result, std::move(converted_packet)); + + // The double remove should be ignored. + ASSERT_EQ(result.size(), (size_t)0); +} + TEST(PointerDataPacketConverterTest, CanHandleThreeFingerGesture) { // Regression test https://github.com/flutter/flutter/issues/20517. TestDelegate delegate;
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 0013657..904a3ea 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm
@@ -2782,79 +2782,6 @@ flutterPlatformViewsController->Reset(); } -- (void)testFlutterPlatformViewForwardingAndDelayingRecognizerFailureCondition { - flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; - - flutter::TaskRunners runners(/*label=*/self.name.UTF8String, - /*platform=*/GetDefaultTaskRunner(), - /*raster=*/GetDefaultTaskRunner(), - /*ui=*/GetDefaultTaskRunner(), - /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared<flutter::PlatformViewsController>(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); - auto platform_view = std::make_unique<flutter::PlatformViewIOS>( - /*delegate=*/mock_delegate, - /*rendering_api=*/mock_delegate.settings_.enable_impeller - ? flutter::IOSRenderingAPI::kMetal - : flutter::IOSRenderingAPI::kSoftware, - /*platform_views_controller=*/flutterPlatformViewsController, - /*task_runners=*/runners, - /*worker_task_runner=*/nil, - /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>()); - - FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = - [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); - FlutterResult result = ^(id result) { - }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); - - XCTAssertNotNil(gMockPlatformView); - - // Find touch inteceptor view - UIView* touchInteceptorView = gMockPlatformView; - while (touchInteceptorView != nil && - ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) { - touchInteceptorView = touchInteceptorView.superview; - } - XCTAssertNotNil(touchInteceptorView); - - // Find ForwardGestureRecognizer - UIGestureRecognizer* forwardingGestureRecognizer = nil; - UIGestureRecognizer* delayingGestureRecognizer = nil; - for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) { - if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) { - forwardingGestureRecognizer = gestureRecognizer; - } - if ([gestureRecognizer isKindOfClass:NSClassFromString(@"FlutterDelayingGestureRecognizer")]) { - delayingGestureRecognizer = gestureRecognizer; - } - } - UIGestureRecognizer* otherGestureRecognizer = OCMClassMock([UIGestureRecognizer class]); - - id flutterViewContoller = OCMClassMock([FlutterViewController class]); - flutterPlatformViewsController->SetFlutterViewController(flutterViewContoller); - - XCTAssertFalse([delayingGestureRecognizer.delegate - gestureRecognizer:delayingGestureRecognizer - shouldBeRequiredToFailByGestureRecognizer:forwardingGestureRecognizer]); - XCTAssertTrue([delayingGestureRecognizer.delegate gestureRecognizer:delayingGestureRecognizer - shouldBeRequiredToFailByGestureRecognizer:otherGestureRecognizer]); - - XCTAssertTrue([delayingGestureRecognizer.delegate gestureRecognizer:delayingGestureRecognizer - shouldRequireFailureOfGestureRecognizer:forwardingGestureRecognizer]); - XCTAssertFalse([delayingGestureRecognizer.delegate gestureRecognizer:delayingGestureRecognizer - shouldRequireFailureOfGestureRecognizer:otherGestureRecognizer]); - - flutterPlatformViewsController->Reset(); -} - - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing { flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm index 90c4d42..5e76654 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm
@@ -654,14 +654,14 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { - // The forwarding gesture recognizer should always get all touch events, so it should not - // require other gesture recognizer to fail. - return otherGestureRecognizer != _forwardingRecognizer; + // The forwarding gesture recognizer should always get all touch events, so it should not be + // required to fail by any other gesture recognizer. + return otherGestureRecognizer != _forwardingRecognizer && otherGestureRecognizer != self; } - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { - return otherGestureRecognizer == _forwardingRecognizer; + return otherGestureRecognizer == self; } - (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
diff --git a/shell/platform/fuchsia/dart/BUILD.gn b/shell/platform/fuchsia/dart/BUILD.gn index b2140f8..b35defc 100644 --- a/shell/platform/fuchsia/dart/BUILD.gn +++ b/shell/platform/fuchsia/dart/BUILD.gn
@@ -76,9 +76,13 @@ deps = [] sources = [ + "async_helper.dart", "config.dart", "expect.dart", + "legacy/async_minitest.dart", + "legacy/minitest.dart", "minitest.dart", + "static_type_helper.dart", "variations.dart", ] }
diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 22c192e..a28e375 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn
@@ -81,6 +81,7 @@ "fl_dart_project_private.h", "fl_engine_private.h", "fl_keyboard_handler.h", + "fl_keyboard_manager.h", "fl_keyboard_pending_event.h", "fl_keyboard_view_delegate.h", "fl_key_event.h", @@ -118,6 +119,7 @@ "fl_key_responder.cc", "fl_keyboard_handler.cc", "fl_keyboard_layout.cc", + "fl_keyboard_manager.cc", "fl_keyboard_pending_event.cc", "fl_keyboard_view_delegate.cc", "fl_message_codec.cc", @@ -217,6 +219,7 @@ "fl_key_embedder_responder_test.cc", "fl_keyboard_handler_test.cc", "fl_keyboard_layout_test.cc", + "fl_keyboard_manager_test.cc", "fl_message_codec_test.cc", "fl_method_channel_test.cc", "fl_method_codec_test.cc",
diff --git a/shell/platform/linux/fl_keyboard_handler.cc b/shell/platform/linux/fl_keyboard_handler.cc index e914925..266b9b1 100644 --- a/shell/platform/linux/fl_keyboard_handler.cc +++ b/shell/platform/linux/fl_keyboard_handler.cc
@@ -4,376 +4,23 @@ #include "flutter/shell/platform/linux/fl_keyboard_handler.h" -#include <array> -#include <cinttypes> -#include <memory> -#include <string> - -#include "flutter/shell/platform/linux/fl_key_channel_responder.h" -#include "flutter/shell/platform/linux/fl_key_embedder_responder.h" -#include "flutter/shell/platform/linux/fl_keyboard_layout.h" -#include "flutter/shell/platform/linux/fl_keyboard_pending_event.h" -#include "flutter/shell/platform/linux/key_mapping.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" -// Turn on this flag to print complete layout data when switching IMEs. The data -// is used in unit tests. -#define DEBUG_PRINT_LAYOUT - static constexpr char kChannelName[] = "flutter/keyboard"; static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; -/* Declarations of private classes */ - -G_DECLARE_FINAL_TYPE(FlKeyboardHandlerUserData, - fl_keyboard_handler_user_data, - FL, - KEYBOARD_HANDLER_USER_DATA, - GObject); - -/* End declarations */ - -namespace { - -static bool is_eascii(uint16_t character) { - return character < 256; -} - -#ifdef DEBUG_PRINT_LAYOUT -// Prints layout entries that will be parsed by `MockLayoutData`. -void debug_format_layout_data(std::string& debug_layout_data, - uint16_t keycode, - uint16_t clue1, - uint16_t clue2) { - if (keycode % 4 == 0) { - debug_layout_data.append(" "); - } - - constexpr int kBufferSize = 30; - char buffer[kBufferSize]; - buffer[0] = 0; - buffer[kBufferSize - 1] = 0; - - snprintf(buffer, kBufferSize, "0x%04x, 0x%04x, ", clue1, clue2); - debug_layout_data.append(buffer); - - if (keycode % 4 == 3) { - snprintf(buffer, kBufferSize, " // 0x%02x", keycode); - debug_layout_data.append(buffer); - } -} -#endif - -} // namespace - -/* Define FlKeyboardHandlerUserData */ - -/** - * FlKeyboardHandlerUserData: - * The user_data used when #FlKeyboardHandler sends event to - * responders. - */ - -struct _FlKeyboardHandlerUserData { - GObject parent_instance; - - // The owner handler. - GWeakRef handler; - uint64_t sequence_id; -}; - -G_DEFINE_TYPE(FlKeyboardHandlerUserData, - fl_keyboard_handler_user_data, - G_TYPE_OBJECT) - -static void fl_keyboard_handler_user_data_dispose(GObject* object) { - g_return_if_fail(FL_IS_KEYBOARD_HANDLER_USER_DATA(object)); - FlKeyboardHandlerUserData* self = FL_KEYBOARD_HANDLER_USER_DATA(object); - - g_weak_ref_clear(&self->handler); - - G_OBJECT_CLASS(fl_keyboard_handler_user_data_parent_class)->dispose(object); -} - -static void fl_keyboard_handler_user_data_class_init( - FlKeyboardHandlerUserDataClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_keyboard_handler_user_data_dispose; -} - -static void fl_keyboard_handler_user_data_init( - FlKeyboardHandlerUserData* self) {} - -// Creates a new FlKeyboardHandlerUserData private class with all information. -static FlKeyboardHandlerUserData* fl_keyboard_handler_user_data_new( - FlKeyboardHandler* handler, - uint64_t sequence_id) { - FlKeyboardHandlerUserData* self = FL_KEYBOARD_HANDLER_USER_DATA( - g_object_new(fl_keyboard_handler_user_data_get_type(), nullptr)); - - g_weak_ref_init(&self->handler, handler); - self->sequence_id = sequence_id; - return self; -} - -/* Define FlKeyboardHandler */ - struct _FlKeyboardHandler { GObject parent_instance; GWeakRef view_delegate; - // An array of #FlKeyResponder. Elements are added with - // #fl_keyboard_handler_add_responder immediately after initialization and are - // automatically released on dispose. - GPtrArray* responder_list; - - // An array of #FlKeyboardPendingEvent. - // - // Its elements are *not* unreferenced when removed. When FlKeyboardHandler is - // disposed, this array will be set with a free_func so that the elements are - // unreferenced when removed. - GPtrArray* pending_responds; - - // An array of #FlKeyboardPendingEvent. - // - // Its elements are unreferenced when removed. - GPtrArray* pending_redispatches; - - // The last sequence ID used. Increased by 1 by every use. - uint64_t last_sequence_id; - - // Record the derived layout. - // - // It is cleared when the platform reports a layout switch. Each entry, - // which corresponds to a group, is only initialized on the arrival of the - // first event for that group that has a goal keycode. - FlKeyboardLayout* derived_layout; - - // A static map from keycodes to all layout goals. - // - // It is set up when the handler is initialized and is not changed ever after. - std::unique_ptr<std::map<uint16_t, const LayoutGoal*>> keycode_to_goals; - - // A static map from logical keys to all mandatory layout goals. - // - // It is set up when the handler is initialized and is not changed ever after. - std::unique_ptr<std::map<uint64_t, const LayoutGoal*>> - logical_to_mandatory_goals; - // The channel used by the framework to query the keyboard pressed state. FlMethodChannel* channel; }; G_DEFINE_TYPE(FlKeyboardHandler, fl_keyboard_handler, G_TYPE_OBJECT); -// This is an exact copy of g_ptr_array_find_with_equal_func. Somehow CI -// reports that can not find symbol g_ptr_array_find_with_equal_func, despite -// the fact that it runs well locally. -static gboolean g_ptr_array_find_with_equal_func1(GPtrArray* haystack, - gconstpointer needle, - GEqualFunc equal_func, - guint* index_) { - guint i; - g_return_val_if_fail(haystack != NULL, FALSE); - if (equal_func == NULL) { - equal_func = g_direct_equal; - } - for (i = 0; i < haystack->len; i++) { - if (equal_func(g_ptr_array_index(haystack, i), needle)) { - if (index_ != NULL) { - *index_ = i; - } - return TRUE; - } - } - - return FALSE; -} - -// Compare a #FlKeyboardPendingEvent with the given sequence_id. -static gboolean compare_pending_by_sequence_id(gconstpointer a, - gconstpointer b) { - FlKeyboardPendingEvent* pending = - FL_KEYBOARD_PENDING_EVENT(const_cast<gpointer>(a)); - uint64_t sequence_id = *reinterpret_cast<const uint64_t*>(b); - return fl_keyboard_pending_event_get_sequence_id(pending) == sequence_id; -} - -// Compare a #FlKeyboardPendingEvent with the given hash. -static gboolean compare_pending_by_hash(gconstpointer a, gconstpointer b) { - FlKeyboardPendingEvent* pending = - FL_KEYBOARD_PENDING_EVENT(const_cast<gpointer>(a)); - uint64_t hash = *reinterpret_cast<const uint64_t*>(b); - return fl_keyboard_pending_event_get_hash(pending) == hash; -} - -// Try to remove a pending event from `pending_redispatches` with the target -// hash. -// -// Returns true if the event is found and removed. -static bool fl_keyboard_handler_remove_redispatched(FlKeyboardHandler* self, - uint64_t hash) { - guint result_index; - gboolean found = g_ptr_array_find_with_equal_func1( - self->pending_redispatches, static_cast<const uint64_t*>(&hash), - compare_pending_by_hash, &result_index); - if (found) { - // The removed object is freed due to `pending_redispatches`'s free_func. - g_ptr_array_remove_index_fast(self->pending_redispatches, result_index); - return TRUE; - } else { - return FALSE; - } -} - -// The callback used by a responder after the event was dispatched. -static void responder_handle_event_callback(bool handled, - gpointer user_data_ptr) { - g_return_if_fail(FL_IS_KEYBOARD_HANDLER_USER_DATA(user_data_ptr)); - FlKeyboardHandlerUserData* user_data = - FL_KEYBOARD_HANDLER_USER_DATA(user_data_ptr); - - g_autoptr(FlKeyboardHandler) self = - FL_KEYBOARD_HANDLER(g_weak_ref_get(&user_data->handler)); - if (self == nullptr) { - return; - } - - g_autoptr(FlKeyboardViewDelegate) view_delegate = - FL_KEYBOARD_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate)); - if (view_delegate == nullptr) { - return; - } - - guint result_index = -1; - gboolean found = g_ptr_array_find_with_equal_func1( - self->pending_responds, &user_data->sequence_id, - compare_pending_by_sequence_id, &result_index); - g_return_if_fail(found); - FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT( - g_ptr_array_index(self->pending_responds, result_index)); - g_return_if_fail(pending != nullptr); - fl_keyboard_pending_event_mark_replied(pending, handled); - // All responders have replied. - if (fl_keyboard_pending_event_is_complete(pending)) { - g_object_unref(user_data_ptr); - gpointer removed = - g_ptr_array_remove_index_fast(self->pending_responds, result_index); - g_return_if_fail(removed == pending); - bool should_redispatch = - !fl_keyboard_pending_event_get_any_handled(pending) && - !fl_keyboard_view_delegate_text_filter_key_press( - view_delegate, fl_keyboard_pending_event_get_event(pending)); - if (should_redispatch) { - g_ptr_array_add(self->pending_redispatches, pending); - fl_keyboard_view_delegate_redispatch_event( - view_delegate, - FL_KEY_EVENT(fl_keyboard_pending_event_get_event(pending))); - } else { - g_object_unref(pending); - } - } -} - -static uint16_t convert_key_to_char(FlKeyboardViewDelegate* view_delegate, - guint keycode, - gint group, - gint level) { - GdkKeymapKey key = {keycode, group, level}; - constexpr int kBmpMax = 0xD7FF; - guint origin = fl_keyboard_view_delegate_lookup_key(view_delegate, &key); - return origin < kBmpMax ? origin : 0xFFFF; -} - -// Make sure that Flutter has derived the layout for the group of the event, -// if the event contains a goal keycode. -static void guarantee_layout(FlKeyboardHandler* self, FlKeyEvent* event) { - g_autoptr(FlKeyboardViewDelegate) view_delegate = - FL_KEYBOARD_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate)); - if (view_delegate == nullptr) { - return; - } - - guint8 group = fl_key_event_get_group(event); - if (fl_keyboard_layout_has_group(self->derived_layout, group)) { - return; - } - if (self->keycode_to_goals->find(fl_key_event_get_keycode(event)) == - self->keycode_to_goals->end()) { - return; - } - - // Clone all mandatory goals. Each goal is removed from this cloned map when - // fulfilled, and the remaining ones will be assigned to a default position. - std::map<uint64_t, const LayoutGoal*> remaining_mandatory_goals = - *self->logical_to_mandatory_goals; - -#ifdef DEBUG_PRINT_LAYOUT - std::string debug_layout_data; - for (uint16_t keycode = 0; keycode < 128; keycode += 1) { - std::vector<uint16_t> this_key_clues = { - convert_key_to_char(view_delegate, keycode, group, 0), - convert_key_to_char(view_delegate, keycode, group, 1), // Shift - }; - debug_format_layout_data(debug_layout_data, keycode, this_key_clues[0], - this_key_clues[1]); - } -#endif - - // It's important to only traverse layout goals instead of all keycodes. - // Some key codes outside of the standard keyboard also gives alpha-numeric - // letters, and will therefore take over mandatory goals from standard - // keyboard keys if they come first. Example: French keyboard digit 1. - for (const LayoutGoal& keycode_goal : layout_goals) { - uint16_t keycode = keycode_goal.keycode; - std::vector<uint16_t> this_key_clues = { - convert_key_to_char(view_delegate, keycode, group, 0), - convert_key_to_char(view_delegate, keycode, group, 1), // Shift - }; - - // The logical key should be the first available clue from below: - // - // - Mandatory goal, if it matches any clue. This ensures that all alnum - // keys can be found somewhere. - // - US layout, if neither clue of the key is EASCII. This ensures that - // there are no non-latin logical keys. - // - A value derived on the fly from keycode & keyval. - for (uint16_t clue : this_key_clues) { - auto matching_goal = remaining_mandatory_goals.find(clue); - if (matching_goal != remaining_mandatory_goals.end()) { - // Found a key that produces a mandatory char. Use it. - g_return_if_fail(fl_keyboard_layout_get_logical_key( - self->derived_layout, group, keycode) == 0); - fl_keyboard_layout_set_logical_key(self->derived_layout, group, keycode, - clue); - remaining_mandatory_goals.erase(matching_goal); - break; - } - } - bool has_any_eascii = - is_eascii(this_key_clues[0]) || is_eascii(this_key_clues[1]); - // See if any produced char meets the requirement as a logical key. - if (fl_keyboard_layout_get_logical_key(self->derived_layout, group, - keycode) == 0 && - !has_any_eascii) { - auto found_us_layout = self->keycode_to_goals->find(keycode); - if (found_us_layout != self->keycode_to_goals->end()) { - fl_keyboard_layout_set_logical_key( - self->derived_layout, group, keycode, - found_us_layout->second->logical_key); - } - } - } - - // Ensure all mandatory goals are assigned. - for (const auto mandatory_goal_iter : remaining_mandatory_goals) { - const LayoutGoal* goal = mandatory_goal_iter.second; - fl_keyboard_layout_set_logical_key(self->derived_layout, group, - goal->keycode, goal->logical_key); - } -} - // Returns the keyboard pressed state. static FlMethodResponse* get_keyboard_state(FlKeyboardHandler* self) { g_autoptr(FlValue) result = fl_value_new_map(); @@ -423,15 +70,7 @@ FlKeyboardHandler* self = FL_KEYBOARD_HANDLER(object); g_weak_ref_clear(&self->view_delegate); - - self->keycode_to_goals.reset(); - self->logical_to_mandatory_goals.reset(); - - g_ptr_array_free(self->responder_list, TRUE); - g_ptr_array_set_free_func(self->pending_responds, g_object_unref); - g_ptr_array_free(self->pending_responds, TRUE); - g_ptr_array_free(self->pending_redispatches, TRUE); - g_clear_object(&self->derived_layout); + g_clear_object(&self->channel); G_OBJECT_CLASS(fl_keyboard_handler_parent_class)->dispose(object); } @@ -440,27 +79,7 @@ G_OBJECT_CLASS(klass)->dispose = fl_keyboard_handler_dispose; } -static void fl_keyboard_handler_init(FlKeyboardHandler* self) { - self->derived_layout = fl_keyboard_layout_new(); - - self->keycode_to_goals = - std::make_unique<std::map<uint16_t, const LayoutGoal*>>(); - self->logical_to_mandatory_goals = - std::make_unique<std::map<uint64_t, const LayoutGoal*>>(); - for (const LayoutGoal& goal : layout_goals) { - (*self->keycode_to_goals)[goal.keycode] = &goal; - if (goal.mandatory) { - (*self->logical_to_mandatory_goals)[goal.logical_key] = &goal; - } - } - - self->responder_list = g_ptr_array_new_with_free_func(g_object_unref); - - self->pending_responds = g_ptr_array_new(); - self->pending_redispatches = g_ptr_array_new_with_free_func(g_object_unref); - - self->last_sequence_id = 1; -} +static void fl_keyboard_handler_init(FlKeyboardHandler* self) {} FlKeyboardHandler* fl_keyboard_handler_new( FlBinaryMessenger* messenger, @@ -472,27 +91,6 @@ g_weak_ref_init(&self->view_delegate, view_delegate); - // The embedder responder must be added before the channel responder. - g_ptr_array_add( - self->responder_list, - FL_KEY_RESPONDER(fl_key_embedder_responder_new( - [](const FlutterKeyEvent* event, FlutterKeyEventCallback callback, - void* callback_user_data, void* send_key_event_user_data) { - FlKeyboardHandler* self = - FL_KEYBOARD_HANDLER(send_key_event_user_data); - g_autoptr(FlKeyboardViewDelegate) view_delegate = - FL_KEYBOARD_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate)); - if (view_delegate == nullptr) { - return; - } - fl_keyboard_view_delegate_send_key_event( - view_delegate, event, callback, callback_user_data); - }, - self))); - g_ptr_array_add(self->responder_list, - FL_KEY_RESPONDER(fl_key_channel_responder_new( - fl_keyboard_view_delegate_get_messenger(view_delegate)))); - // Setup the flutter/keyboard channel. g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); self->channel = @@ -501,70 +99,3 @@ self, nullptr); return self; } - -gboolean fl_keyboard_handler_handle_event(FlKeyboardHandler* self, - FlKeyEvent* event) { - g_return_val_if_fail(FL_IS_KEYBOARD_HANDLER(self), FALSE); - g_return_val_if_fail(event != nullptr, FALSE); - - guarantee_layout(self, event); - - uint64_t incoming_hash = fl_key_event_hash(event); - if (fl_keyboard_handler_remove_redispatched(self, incoming_hash)) { - return FALSE; - } - - FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( - event, ++self->last_sequence_id, self->responder_list->len); - - g_ptr_array_add(self->pending_responds, pending); - FlKeyboardHandlerUserData* user_data = fl_keyboard_handler_user_data_new( - self, fl_keyboard_pending_event_get_sequence_id(pending)); - uint64_t specified_logical_key = fl_keyboard_layout_get_logical_key( - self->derived_layout, fl_key_event_get_group(event), - fl_key_event_get_keycode(event)); - for (guint i = 0; i < self->responder_list->len; i++) { - FlKeyResponder* responder = - FL_KEY_RESPONDER(g_ptr_array_index(self->responder_list, i)); - fl_key_responder_handle_event(responder, event, - responder_handle_event_callback, user_data, - specified_logical_key); - } - - return TRUE; -} - -gboolean fl_keyboard_handler_is_state_clear(FlKeyboardHandler* self) { - g_return_val_if_fail(FL_IS_KEYBOARD_HANDLER(self), FALSE); - return self->pending_responds->len == 0 && - self->pending_redispatches->len == 0; -} - -void fl_keyboard_handler_sync_modifier_if_needed(FlKeyboardHandler* self, - guint state, - double event_time) { - g_return_if_fail(FL_IS_KEYBOARD_HANDLER(self)); - - // The embedder responder is the first element in - // FlKeyboardHandler.responder_list. - FlKeyEmbedderResponder* responder = - FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0)); - fl_key_embedder_responder_sync_modifiers_if_needed(responder, state, - event_time); -} - -GHashTable* fl_keyboard_handler_get_pressed_state(FlKeyboardHandler* self) { - g_return_val_if_fail(FL_IS_KEYBOARD_HANDLER(self), nullptr); - - // The embedder responder is the first element in - // FlKeyboardHandler.responder_list. - FlKeyEmbedderResponder* responder = - FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0)); - return fl_key_embedder_responder_get_pressed_state(responder); -} - -void fl_keyboard_handler_notify_layout_changed(FlKeyboardHandler* self) { - g_return_if_fail(FL_IS_KEYBOARD_HANDLER(self)); - g_clear_object(&self->derived_layout); - self->derived_layout = fl_keyboard_layout_new(); -}
diff --git a/shell/platform/linux/fl_keyboard_handler.h b/shell/platform/linux/fl_keyboard_handler.h index 0d551d6..57da5e9 100644 --- a/shell/platform/linux/fl_keyboard_handler.h +++ b/shell/platform/linux/fl_keyboard_handler.h
@@ -8,6 +8,7 @@ #include <gdk/gdk.h> #include "flutter/shell/platform/linux/fl_keyboard_view_delegate.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" G_BEGIN_DECLS @@ -21,17 +22,7 @@ /** * FlKeyboardHandler: * - * Processes keyboard events and cooperate with `TextInputHandler`. - * - * A keyboard event goes through a few sections, each can choose to handle the - * event, and only unhandled events can move to the next section: - * - * - Keyboard: Dispatch to the embedder responder and the channel responder - * simultaneously. After both responders have responded (asynchronously), the - * event is considered handled if either responder handles it. - * - Text input: Events are sent to IM filter (usually owned by - * `TextInputHandler`) and are handled synchronously. - * - Redispatching: Events are inserted back to the system for redispatching. + * Provides the channel to receive keyboard requests from the Dart code. */ /** @@ -47,60 +38,6 @@ FlBinaryMessenger* messenger, FlKeyboardViewDelegate* view_delegate); -/** - * fl_keyboard_handler_handle_event: - * @handler: the #FlKeyboardHandler self. - * @event: the event to be dispatched. It is usually a wrap of a GdkEventKey. - * This event will be managed and released by #FlKeyboardHandler. - * - * Make the handler process a system key event. This might eventually send - * messages to the framework, trigger text input effects, or redispatch the - * event back to the system. - */ -gboolean fl_keyboard_handler_handle_event(FlKeyboardHandler* handler, - FlKeyEvent* event); - -/** - * fl_keyboard_handler_is_state_clear: - * @handler: the #FlKeyboardHandler self. - * - * A debug-only method that queries whether the handler's various states are - * cleared, i.e. no pending events for redispatching or for responding. - * - * Returns: true if the handler's various states are cleared. - */ -gboolean fl_keyboard_handler_is_state_clear(FlKeyboardHandler* handler); - -/** - * fl_keyboard_handler_sync_modifier_if_needed: - * @handler: the #FlKeyboardHandler self. - * @state: the state of the modifiers mask. - * @event_time: the time attribute of the incoming GDK event. - * - * If needed, synthesize modifier keys up and down event by comparing their - * current pressing states with the given modifiers mask. - */ -void fl_keyboard_handler_sync_modifier_if_needed(FlKeyboardHandler* handler, - guint state, - double event_time); - -/** - * fl_keyboard_handler_get_pressed_state: - * @handler: the #FlKeyboardHandler self. - * - * Returns the keyboard pressed state. The hash table contains one entry per - * pressed keys, mapping from the logical key to the physical key.* - */ -GHashTable* fl_keyboard_handler_get_pressed_state(FlKeyboardHandler* handler); - -/** - * fl_keyboard_handler_notify_layout_changed: - * @handler: the #FlKeyboardHandler self. - * - * Notify the handler the keyboard layout has changed. - */ -void fl_keyboard_handler_notify_layout_changed(FlKeyboardHandler* handler); - G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_HANDLER_H_
diff --git a/shell/platform/linux/fl_keyboard_handler_test.cc b/shell/platform/linux/fl_keyboard_handler_test.cc index f0e9815..a4d9278 100644 --- a/shell/platform/linux/fl_keyboard_handler_test.cc +++ b/shell/platform/linux/fl_keyboard_handler_test.cc
@@ -4,143 +4,26 @@ #include "flutter/shell/platform/linux/fl_keyboard_handler.h" -#include <cstring> -#include <vector> - -#include "flutter/shell/platform/embedder/test_utils/key_codes.g.h" -#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_method_codec_private.h" -#include "flutter/shell/platform/linux/key_mapping.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" -#include "flutter/shell/platform/linux/testing/fl_test.h" #include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" -#include "flutter/shell/platform/linux/testing/mock_text_input_handler.h" -#include "flutter/testing/testing.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -// Define compound `expect` in macros. If they were defined in functions, the -// stacktrace wouldn't print where the function is called in the unit tests. - -#define EXPECT_KEY_EVENT(RECORD, TYPE, PHYSICAL, LOGICAL, CHAR, SYNTHESIZED) \ - EXPECT_EQ((RECORD).type, CallRecord::kKeyCallEmbedder); \ - EXPECT_EQ((RECORD).event->type, (TYPE)); \ - EXPECT_EQ((RECORD).event->physical, (PHYSICAL)); \ - EXPECT_EQ((RECORD).event->logical, (LOGICAL)); \ - EXPECT_STREQ((RECORD).event->character, (CHAR)); \ - EXPECT_EQ((RECORD).event->synthesized, (SYNTHESIZED)); - -#define VERIFY_DOWN(OUT_LOGICAL, OUT_CHAR) \ - EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); \ - EXPECT_EQ(call_records[0].event->type, kFlutterKeyEventTypeDown); \ - EXPECT_EQ(call_records[0].event->logical, (OUT_LOGICAL)); \ - EXPECT_STREQ(call_records[0].event->character, (OUT_CHAR)); \ - EXPECT_EQ(call_records[0].event->synthesized, false); \ - call_records.clear() - -namespace { -using ::flutter::testing::keycodes::kLogicalAltLeft; -using ::flutter::testing::keycodes::kLogicalBracketLeft; -using ::flutter::testing::keycodes::kLogicalComma; -using ::flutter::testing::keycodes::kLogicalControlLeft; -using ::flutter::testing::keycodes::kLogicalDigit1; -using ::flutter::testing::keycodes::kLogicalKeyA; -using ::flutter::testing::keycodes::kLogicalKeyB; -using ::flutter::testing::keycodes::kLogicalKeyM; -using ::flutter::testing::keycodes::kLogicalKeyQ; -using ::flutter::testing::keycodes::kLogicalMetaLeft; -using ::flutter::testing::keycodes::kLogicalMinus; -using ::flutter::testing::keycodes::kLogicalParenthesisRight; -using ::flutter::testing::keycodes::kLogicalSemicolon; -using ::flutter::testing::keycodes::kLogicalShiftLeft; -using ::flutter::testing::keycodes::kLogicalUnderscore; - -using ::flutter::testing::keycodes::kPhysicalAltLeft; -using ::flutter::testing::keycodes::kPhysicalControlLeft; -using ::flutter::testing::keycodes::kPhysicalKeyA; -using ::flutter::testing::keycodes::kPhysicalKeyB; -using ::flutter::testing::keycodes::kPhysicalMetaLeft; -using ::flutter::testing::keycodes::kPhysicalShiftLeft; - -// Hardware key codes. -typedef std::function<void(bool handled)> AsyncKeyCallback; -typedef std::function<void(AsyncKeyCallback callback)> ChannelCallHandler; -typedef std::function<void(const FlutterKeyEvent* event, - AsyncKeyCallback callback)> - EmbedderCallHandler; -typedef std::function<void(FlKeyEvent*)> RedispatchHandler; - -// A type that can record all kinds of effects that the keyboard handler -// triggers. -// -// An instance of `CallRecord` might not have all the fields filled. -typedef struct { - enum { - kKeyCallEmbedder, - kKeyCallChannel, - } type; - - AsyncKeyCallback callback; - std::unique_ptr<FlutterKeyEvent> event; - std::unique_ptr<char[]> event_character; -} CallRecord; - -// Clone a C-string. -// -// Must be deleted by delete[]. -char* cloneString(const char* source) { - if (source == nullptr) { - return nullptr; - } - size_t charLen = strlen(source); - char* target = new char[charLen + 1]; - strncpy(target, source, charLen + 1); - return target; -} - -constexpr guint16 kKeyCodeKeyA = 0x26u; -constexpr guint16 kKeyCodeKeyB = 0x38u; -constexpr guint16 kKeyCodeKeyM = 0x3au; -constexpr guint16 kKeyCodeDigit1 = 0x0au; -constexpr guint16 kKeyCodeMinus = 0x14u; -constexpr guint16 kKeyCodeSemicolon = 0x2fu; -constexpr guint16 kKeyCodeKeyLeftBracket = 0x22u; - -static constexpr char kKeyEventChannelName[] = "flutter/keyevent"; static constexpr char kKeyboardChannelName[] = "flutter/keyboard"; static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; static constexpr uint64_t kMockPhysicalKey = 42; static constexpr uint64_t kMockLogicalKey = 42; -// All key clues for a keyboard layout. -// -// The index is (keyCode * 2 + hasShift), where each value is the character for -// this key (GTK only supports UTF-16.) Since the maximum keycode of interest -// is 128, it has a total of 256 entries.. -typedef std::array<uint32_t, 256> MockGroupLayoutData; -typedef std::vector<const MockGroupLayoutData*> MockLayoutData; - -extern const MockLayoutData kLayoutUs; -extern const MockLayoutData kLayoutRussian; -extern const MockLayoutData kLayoutFrench; - G_BEGIN_DECLS -G_DECLARE_FINAL_TYPE(FlMockViewDelegate, - fl_mock_view_delegate, +G_DECLARE_FINAL_TYPE(FlMockKeyboardHandlerDelegate, + fl_mock_keyboard_handler_delegate, FL, - MOCK_VIEW_DELEGATE, + MOCK_KEYBOARD_HANDLER_DELEGATE, GObject); -G_DECLARE_FINAL_TYPE(FlMockKeyBinaryMessenger, - fl_mock_key_binary_messenger, - FL, - MOCK_KEY_BINARY_MESSENGER, - GObject) - G_END_DECLS MATCHER_P(MethodSuccessResponse, result, "") { @@ -156,243 +39,26 @@ return false; } -/***** FlMockKeyBinaryMessenger *****/ -/* Mock a binary messenger that only processes messages from the embedding on - * the key event channel, and does so according to the callback set by - * fl_mock_key_binary_messenger_set_callback_handler */ - -struct _FlMockKeyBinaryMessenger { +struct _FlMockKeyboardHandlerDelegate { GObject parent_instance; }; -struct FlMockKeyBinaryMessengerPrivate { - ChannelCallHandler callback_handler; -}; - -static void fl_mock_key_binary_messenger_iface_init( - FlBinaryMessengerInterface* iface); - -G_DEFINE_TYPE_WITH_CODE( - FlMockKeyBinaryMessenger, - fl_mock_key_binary_messenger, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(fl_binary_messenger_get_type(), - fl_mock_key_binary_messenger_iface_init); - G_ADD_PRIVATE(FlMockKeyBinaryMessenger)) - -#define FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(obj) \ - static_cast<FlMockKeyBinaryMessengerPrivate*>( \ - fl_mock_key_binary_messenger_get_instance_private( \ - FL_MOCK_KEY_BINARY_MESSENGER(obj))) - -static void fl_mock_key_binary_messenger_init(FlMockKeyBinaryMessenger* self) { - FlMockKeyBinaryMessengerPrivate* priv = - FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(self); - new (priv) FlMockKeyBinaryMessengerPrivate(); -} - -static void fl_mock_key_binary_messenger_dispose(GObject* object) { - FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(object) - ->~FlMockKeyBinaryMessengerPrivate(); - - G_OBJECT_CLASS(fl_mock_key_binary_messenger_parent_class)->dispose(object); -} - -static void fl_mock_key_binary_messenger_class_init( - FlMockKeyBinaryMessengerClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_mock_key_binary_messenger_dispose; -} - -static void fl_mock_key_binary_messenger_send_on_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data) { - FlMockKeyBinaryMessenger* self = FL_MOCK_KEY_BINARY_MESSENGER(messenger); - - if (callback != nullptr) { - EXPECT_STREQ(channel, kKeyEventChannelName); - FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(self)->callback_handler( - [self, cancellable, callback, user_data](bool handled) { - g_autoptr(GTask) task = - g_task_new(self, cancellable, callback, user_data); - g_autoptr(FlValue) result = fl_value_new_map(); - fl_value_set_string_take(result, "handled", - fl_value_new_bool(handled)); - g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - g_autoptr(GError) error = nullptr; - GBytes* data = fl_message_codec_encode_message( - FL_MESSAGE_CODEC(codec), result, &error); - - g_task_return_pointer( - task, data, reinterpret_cast<GDestroyNotify>(g_bytes_unref)); - }); - } -} - -static GBytes* fl_mock_key_binary_messenger_send_on_channel_finish( - FlBinaryMessenger* messenger, - GAsyncResult* result, - GError** error) { - return static_cast<GBytes*>(g_task_propagate_pointer(G_TASK(result), error)); -} - -static void fl_mock_binary_messenger_resize_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - int64_t new_size) { - // Mock implementation. Do nothing. -} - -static void fl_mock_binary_messenger_set_warns_on_channel_overflow( - FlBinaryMessenger* messenger, - const gchar* channel, - bool warns) { - // Mock implementation. Do nothing. -} - -static void fl_mock_key_binary_messenger_iface_init( - FlBinaryMessengerInterface* iface) { - iface->set_message_handler_on_channel = - [](FlBinaryMessenger* messenger, const gchar* channel, - FlBinaryMessengerMessageHandler handler, gpointer user_data, - GDestroyNotify destroy_notify) { - EXPECT_STREQ(channel, kKeyEventChannelName); - // No need to mock. The key event channel expects no incoming messages - // from the framework. - }; - iface->send_response = [](FlBinaryMessenger* messenger, - FlBinaryMessengerResponseHandle* response_handle, - GBytes* response, GError** error) -> gboolean { - // The key event channel expects no incoming messages from the framework, - // hence no responses either. - g_return_val_if_reached(TRUE); - return TRUE; - }; - iface->send_on_channel = fl_mock_key_binary_messenger_send_on_channel; - iface->send_on_channel_finish = - fl_mock_key_binary_messenger_send_on_channel_finish; - iface->resize_channel = fl_mock_binary_messenger_resize_channel; - iface->set_warns_on_channel_overflow = - fl_mock_binary_messenger_set_warns_on_channel_overflow; -} - -static FlMockKeyBinaryMessenger* fl_mock_key_binary_messenger_new() { - FlMockKeyBinaryMessenger* self = FL_MOCK_KEY_BINARY_MESSENGER( - g_object_new(fl_mock_key_binary_messenger_get_type(), NULL)); - - // Added to stop compiler complaining about an unused function. - FL_IS_MOCK_KEY_BINARY_MESSENGER(self); - - return self; -} - -static void fl_mock_key_binary_messenger_set_callback_handler( - FlMockKeyBinaryMessenger* self, - ChannelCallHandler handler) { - FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(self)->callback_handler = - std::move(handler); -} - -/***** FlMockViewDelegate *****/ - -struct _FlMockViewDelegate { - GObject parent_instance; -}; - -struct FlMockViewDelegatePrivate { - FlMockKeyBinaryMessenger* messenger; - EmbedderCallHandler embedder_handler; - bool text_filter_result; - RedispatchHandler redispatch_handler; - const MockLayoutData* layout_data; -}; - -static void fl_mock_view_keyboard_delegate_iface_init( +static void fl_mock_keyboard_handler_delegate_keyboard_view_delegate_iface_init( FlKeyboardViewDelegateInterface* iface); G_DEFINE_TYPE_WITH_CODE( - FlMockViewDelegate, - fl_mock_view_delegate, + FlMockKeyboardHandlerDelegate, + fl_mock_keyboard_handler_delegate, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(), - fl_mock_view_keyboard_delegate_iface_init); - G_ADD_PRIVATE(FlMockViewDelegate)) + G_IMPLEMENT_INTERFACE( + fl_keyboard_view_delegate_get_type(), + fl_mock_keyboard_handler_delegate_keyboard_view_delegate_iface_init)) -#define FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(obj) \ - static_cast<FlMockViewDelegatePrivate*>( \ - fl_mock_view_delegate_get_instance_private(FL_MOCK_VIEW_DELEGATE(obj))) +static void fl_mock_keyboard_handler_delegate_init( + FlMockKeyboardHandlerDelegate* self) {} -static void fl_mock_view_delegate_init(FlMockViewDelegate* self) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self); - new (priv) FlMockViewDelegatePrivate(); -} - -static void fl_mock_view_delegate_dispose(GObject* object) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(object); - - FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(object)->~FlMockViewDelegatePrivate(); - g_clear_object(&priv->messenger); - - G_OBJECT_CLASS(fl_mock_view_delegate_parent_class)->dispose(object); -} - -static void fl_mock_view_delegate_class_init(FlMockViewDelegateClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_mock_view_delegate_dispose; -} - -static void fl_mock_view_keyboard_send_key_event( - FlKeyboardViewDelegate* view_delegate, - const FlutterKeyEvent* event, - FlutterKeyEventCallback callback, - void* user_data) { - FlMockViewDelegatePrivate* priv = - FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_delegate); - priv->embedder_handler(event, [callback, user_data](bool handled) { - if (callback != nullptr) { - callback(handled, user_data); - } - }); -} - -static gboolean fl_mock_view_keyboard_text_filter_key_press( - FlKeyboardViewDelegate* view_delegate, - FlKeyEvent* event) { - FlMockViewDelegatePrivate* priv = - FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_delegate); - return priv->text_filter_result; -} - -static FlBinaryMessenger* fl_mock_view_keyboard_get_messenger( - FlKeyboardViewDelegate* view_delegate) { - FlMockViewDelegatePrivate* priv = - FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_delegate); - return FL_BINARY_MESSENGER(priv->messenger); -} - -static void fl_mock_view_keyboard_redispatch_event( - FlKeyboardViewDelegate* view_delegate, - FlKeyEvent* event) { - FlMockViewDelegatePrivate* priv = - FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_delegate); - if (priv->redispatch_handler) { - priv->redispatch_handler(event); - } -} - -static guint fl_mock_view_keyboard_lookup_key(FlKeyboardViewDelegate* delegate, - const GdkKeymapKey* key) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(delegate); - guint8 group = static_cast<guint8>(key->group); - EXPECT_LT(group, priv->layout_data->size()); - const MockGroupLayoutData* group_layout = (*priv->layout_data)[group]; - EXPECT_TRUE(group_layout != nullptr); - EXPECT_TRUE(key->level == 0 || key->level == 1); - bool shift = key->level == 1; - return (*group_layout)[key->keycode * 2 + shift]; -} +static void fl_mock_keyboard_handler_delegate_class_init( + FlMockKeyboardHandlerDelegateClass* klass) {} static GHashTable* fl_mock_view_keyboard_get_keyboard_state( FlKeyboardViewDelegate* view_delegate) { @@ -403,620 +69,27 @@ return result; } -static void fl_mock_view_keyboard_delegate_iface_init( +static void fl_mock_keyboard_handler_delegate_keyboard_view_delegate_iface_init( FlKeyboardViewDelegateInterface* iface) { - iface->send_key_event = fl_mock_view_keyboard_send_key_event; - iface->text_filter_key_press = fl_mock_view_keyboard_text_filter_key_press; - iface->get_messenger = fl_mock_view_keyboard_get_messenger; - iface->redispatch_event = fl_mock_view_keyboard_redispatch_event; - iface->lookup_key = fl_mock_view_keyboard_lookup_key; iface->get_keyboard_state = fl_mock_view_keyboard_get_keyboard_state; } -static FlMockViewDelegate* fl_mock_view_delegate_new() { - FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE( - g_object_new(fl_mock_view_delegate_get_type(), nullptr)); +static FlMockKeyboardHandlerDelegate* fl_mock_keyboard_handler_delegate_new() { + FlMockKeyboardHandlerDelegate* self = FL_MOCK_KEYBOARD_HANDLER_DELEGATE( + g_object_new(fl_mock_keyboard_handler_delegate_get_type(), nullptr)); // Added to stop compiler complaining about an unused function. - FL_IS_MOCK_VIEW_DELEGATE(self); - - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self); - priv->messenger = fl_mock_key_binary_messenger_new(); + FL_IS_MOCK_KEYBOARD_HANDLER_DELEGATE(self); return self; } -static void fl_mock_view_set_embedder_handler(FlMockViewDelegate* self, - EmbedderCallHandler handler) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self); - priv->embedder_handler = std::move(handler); -} - -static void fl_mock_view_set_text_filter_result(FlMockViewDelegate* self, - bool result) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self); - priv->text_filter_result = result; -} - -static void fl_mock_view_set_redispatch_handler(FlMockViewDelegate* self, - RedispatchHandler handler) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self); - priv->redispatch_handler = std::move(handler); -} - -static void fl_mock_view_set_layout(FlMockViewDelegate* self, - const MockLayoutData* layout) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self); - priv->layout_data = layout; -} - -/***** End FlMockViewDelegate *****/ - -class KeyboardTester { - public: - KeyboardTester() { - ::testing::NiceMock<flutter::testing::MockBinaryMessenger> messenger; - - view_ = fl_mock_view_delegate_new(); - respondToEmbedderCallsWith(false); - respondToChannelCallsWith(false); - respondToTextInputWith(false); - setLayout(kLayoutUs); - - handler_ = - fl_keyboard_handler_new(messenger, FL_KEYBOARD_VIEW_DELEGATE(view_)); - } - - ~KeyboardTester() { - g_clear_object(&view_); - g_clear_object(&handler_); - g_clear_pointer(&redispatched_events_, g_ptr_array_unref); - } - - FlKeyboardHandler* handler() { return handler_; } - - // Block until all GdkMainLoop messages are processed, which is basically - // used only for channel messages. - void flushChannelMessages() { - GMainLoop* loop = g_main_loop_new(nullptr, 0); - g_idle_add(_flushChannelMessagesCb, loop); - g_main_loop_run(loop); - } - - // Dispatch each of the given events, expect their results to be false - // (unhandled), and clear the event array. - // - // Returns the number of events redispatched. If any result is unexpected - // (handled), return a minus number `-x` instead, where `x` is the index of - // the first unexpected redispatch. - int redispatchEventsAndClear(GPtrArray* events) { - guint event_count = events->len; - int first_error = -1; - during_redispatch_ = true; - for (guint event_id = 0; event_id < event_count; event_id += 1) { - FlKeyEvent* event = FL_KEY_EVENT(g_ptr_array_index(events, event_id)); - bool handled = fl_keyboard_handler_handle_event(handler_, event); - EXPECT_FALSE(handled); - if (handled) { - first_error = first_error == -1 ? event_id : first_error; - } - } - during_redispatch_ = false; - g_ptr_array_set_size(events, 0); - return first_error < 0 ? event_count : -first_error; - } - - void respondToEmbedderCallsWith(bool response) { - fl_mock_view_set_embedder_handler( - view_, [response, this](const FlutterKeyEvent* event, - const AsyncKeyCallback& callback) { - EXPECT_FALSE(during_redispatch_); - callback(response); - }); - } - - void recordEmbedderCallsTo(std::vector<CallRecord>& storage) { - fl_mock_view_set_embedder_handler( - view_, [&storage, this](const FlutterKeyEvent* event, - AsyncKeyCallback callback) { - EXPECT_FALSE(during_redispatch_); - auto new_event = std::make_unique<FlutterKeyEvent>(*event); - char* new_event_character = cloneString(event->character); - new_event->character = new_event_character; - storage.push_back(CallRecord{ - .type = CallRecord::kKeyCallEmbedder, - .callback = std::move(callback), - .event = std::move(new_event), - .event_character = std::unique_ptr<char[]>(new_event_character), - }); - }); - } - - void respondToEmbedderCallsWithAndRecordsTo( - bool response, - std::vector<CallRecord>& storage) { - fl_mock_view_set_embedder_handler( - view_, [&storage, response, this](const FlutterKeyEvent* event, - const AsyncKeyCallback& callback) { - EXPECT_FALSE(during_redispatch_); - auto new_event = std::make_unique<FlutterKeyEvent>(*event); - char* new_event_character = cloneString(event->character); - new_event->character = new_event_character; - storage.push_back(CallRecord{ - .type = CallRecord::kKeyCallEmbedder, - .event = std::move(new_event), - .event_character = std::unique_ptr<char[]>(new_event_character), - }); - callback(response); - }); - } - - void respondToChannelCallsWith(bool response) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_); - - fl_mock_key_binary_messenger_set_callback_handler( - priv->messenger, [response, this](const AsyncKeyCallback& callback) { - EXPECT_FALSE(during_redispatch_); - callback(response); - }); - } - - void recordChannelCallsTo(std::vector<CallRecord>& storage) { - FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_); - - fl_mock_key_binary_messenger_set_callback_handler( - priv->messenger, [&storage, this](AsyncKeyCallback callback) { - EXPECT_FALSE(during_redispatch_); - storage.push_back(CallRecord{ - .type = CallRecord::kKeyCallChannel, - .callback = std::move(callback), - }); - }); - } - - void respondToTextInputWith(bool response) { - fl_mock_view_set_text_filter_result(view_, response); - } - - void recordRedispatchedEventsTo(GPtrArray* storage) { - redispatched_events_ = g_ptr_array_ref(storage); - fl_mock_view_set_redispatch_handler(view_, [this](FlKeyEvent* key) { - g_ptr_array_add(redispatched_events_, g_object_ref(key)); - }); - } - - void setLayout(const MockLayoutData& layout) { - fl_mock_view_set_layout(view_, &layout); - if (handler_ != nullptr) { - fl_keyboard_handler_notify_layout_changed(handler_); - } - } - - private: - FlMockViewDelegate* view_; - FlKeyboardHandler* handler_ = nullptr; - GPtrArray* redispatched_events_ = nullptr; - bool during_redispatch_ = false; - - static gboolean _flushChannelMessagesCb(gpointer data) { - g_autoptr(GMainLoop) loop = reinterpret_cast<GMainLoop*>(data); - g_main_loop_quit(loop); - return FALSE; - } -}; - -// Make sure that the keyboard can be disposed without crashes when there are -// unresolved pending events. -TEST(FlKeyboardHandlerTest, DisposeWithUnresolvedPends) { - KeyboardTester tester; - std::vector<CallRecord> call_records; - - // Record calls so that they aren't responded. - tester.recordEmbedderCallsTo(call_records); - g_autoptr(FlKeyEvent) event1 = fl_key_event_new( - 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - fl_keyboard_handler_handle_event(tester.handler(), event1); - - tester.respondToEmbedderCallsWith(true); - g_autoptr(FlKeyEvent) event2 = fl_key_event_new( - 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - fl_keyboard_handler_handle_event(tester.handler(), event2); - - tester.flushChannelMessages(); - - // Passes if the cleanup does not crash. -} - -TEST(FlKeyboardHandlerTest, SingleDelegateWithAsyncResponds) { - KeyboardTester tester; - std::vector<CallRecord> call_records; - g_autoptr(GPtrArray) redispatched = - g_ptr_array_new_with_free_func(g_object_unref); - - gboolean handler_handled = false; - - /// Test 1: One event that is handled by the framework - tester.recordEmbedderCallsTo(call_records); - tester.recordRedispatchedEventsTo(redispatched); - - // Dispatch a key event - g_autoptr(FlKeyEvent) event1 = fl_key_event_new( - 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1); - tester.flushChannelMessages(); - EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched->len, 0u); - EXPECT_EQ(call_records.size(), 1u); - EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, - kLogicalKeyA, "a", false); - - call_records[0].callback(true); - tester.flushChannelMessages(); - EXPECT_EQ(redispatched->len, 0u); - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); - call_records.clear(); - - /// Test 2: Two events that are unhandled by the framework - g_autoptr(FlKeyEvent) event2 = fl_key_event_new( - 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2); - tester.flushChannelMessages(); - EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched->len, 0u); - EXPECT_EQ(call_records.size(), 1u); - EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, - kLogicalKeyA, nullptr, false); - - // Dispatch another key event - g_autoptr(FlKeyEvent) event3 = fl_key_event_new( - 0, TRUE, kKeyCodeKeyB, GDK_KEY_b, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event3); - tester.flushChannelMessages(); - EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched->len, 0u); - EXPECT_EQ(call_records.size(), 2u); - EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeDown, kPhysicalKeyB, - kLogicalKeyB, "b", false); - - // Resolve the second event first to test out-of-order response - call_records[1].callback(false); - EXPECT_EQ(redispatched->len, 1u); - EXPECT_EQ( - fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 0))), - 0x62u); - call_records[0].callback(false); - tester.flushChannelMessages(); - EXPECT_EQ(redispatched->len, 2u); - EXPECT_EQ( - fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 1))), - 0x61u); - - EXPECT_FALSE(fl_keyboard_handler_is_state_clear(tester.handler())); - call_records.clear(); - - // Resolve redispatches - EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 2); - tester.flushChannelMessages(); - EXPECT_EQ(call_records.size(), 0u); - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); - - /// Test 3: Dispatch the same event again to ensure that prevention from - /// redispatching only works once. - g_autoptr(FlKeyEvent) event4 = fl_key_event_new( - 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event4); - tester.flushChannelMessages(); - EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched->len, 0u); - EXPECT_EQ(call_records.size(), 1u); - - call_records[0].callback(true); - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); -} - -TEST(FlKeyboardHandlerTest, SingleDelegateWithSyncResponds) { - KeyboardTester tester; - gboolean handler_handled = false; - std::vector<CallRecord> call_records; - g_autoptr(GPtrArray) redispatched = - g_ptr_array_new_with_free_func(g_object_unref); - - /// Test 1: One event that is handled by the framework - tester.respondToEmbedderCallsWithAndRecordsTo(true, call_records); - tester.recordRedispatchedEventsTo(redispatched); - - // Dispatch a key event - g_autoptr(FlKeyEvent) event1 = fl_key_event_new( - 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1); - tester.flushChannelMessages(); - EXPECT_EQ(handler_handled, true); - EXPECT_EQ(call_records.size(), 1u); - EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, - kLogicalKeyA, "a", false); - EXPECT_EQ(redispatched->len, 0u); - call_records.clear(); - - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); - g_ptr_array_set_size(redispatched, 0); - - /// Test 2: An event unhandled by the framework - tester.respondToEmbedderCallsWithAndRecordsTo(false, call_records); - g_autoptr(FlKeyEvent) event2 = fl_key_event_new( - 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2); - tester.flushChannelMessages(); - EXPECT_EQ(handler_handled, true); - EXPECT_EQ(call_records.size(), 1u); - EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, - kLogicalKeyA, nullptr, false); - EXPECT_EQ(redispatched->len, 1u); - call_records.clear(); - - EXPECT_FALSE(fl_keyboard_handler_is_state_clear(tester.handler())); - - EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1); - EXPECT_EQ(call_records.size(), 0u); - - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); -} - -TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) { - KeyboardTester tester; - std::vector<CallRecord> call_records; - g_autoptr(GPtrArray) redispatched = - g_ptr_array_new_with_free_func(g_object_unref); - - gboolean handler_handled = false; - - tester.recordEmbedderCallsTo(call_records); - tester.recordChannelCallsTo(call_records); - tester.recordRedispatchedEventsTo(redispatched); - - /// Test 1: One delegate responds true, the other false - - g_autoptr(FlKeyEvent) event1 = fl_key_event_new( - 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1); - - EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched->len, 0u); - EXPECT_EQ(call_records.size(), 2u); - - EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); - EXPECT_EQ(call_records[1].type, CallRecord::kKeyCallChannel); - - call_records[0].callback(true); - call_records[1].callback(false); - tester.flushChannelMessages(); - EXPECT_EQ(redispatched->len, 0u); - - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); - call_records.clear(); - - /// Test 2: All delegates respond false - g_autoptr(FlKeyEvent) event2 = fl_key_event_new( - 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2); - - EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched->len, 0u); - EXPECT_EQ(call_records.size(), 2u); - - EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); - EXPECT_EQ(call_records[1].type, CallRecord::kKeyCallChannel); - - call_records[0].callback(false); - call_records[1].callback(false); - - call_records.clear(); - - // Resolve redispatch - tester.flushChannelMessages(); - EXPECT_EQ(redispatched->len, 1u); - EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1); - EXPECT_EQ(call_records.size(), 0u); - - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); -} - -TEST(FlKeyboardHandlerTest, TextInputHandlerReturnsFalse) { - KeyboardTester tester; - g_autoptr(GPtrArray) redispatched = - g_ptr_array_new_with_free_func(g_object_unref); - gboolean handler_handled = false; - tester.recordRedispatchedEventsTo(redispatched); - tester.respondToTextInputWith(false); - - // Dispatch a key event. - g_autoptr(FlKeyEvent) event = fl_key_event_new( - 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event); - tester.flushChannelMessages(); - EXPECT_EQ(handler_handled, true); - // The event was redispatched because no one handles it. - EXPECT_EQ(redispatched->len, 1u); - - // Resolve redispatched event. - EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1); - - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); -} - -TEST(FlKeyboardHandlerTest, TextInputHandlerReturnsTrue) { - KeyboardTester tester; - g_autoptr(GPtrArray) redispatched = - g_ptr_array_new_with_free_func(g_object_unref); - gboolean handler_handled = false; - tester.recordRedispatchedEventsTo(redispatched); - tester.respondToTextInputWith(true); - - // Dispatch a key event. - g_autoptr(FlKeyEvent) event = fl_key_event_new( - 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event); - tester.flushChannelMessages(); - EXPECT_EQ(handler_handled, true); - // The event was not redispatched because handler handles it. - EXPECT_EQ(redispatched->len, 0u); - - EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); -} - -TEST(FlKeyboardHandlerTest, CorrectLogicalKeyForLayouts) { - KeyboardTester tester; - - std::vector<CallRecord> call_records; - tester.recordEmbedderCallsTo(call_records); - - auto sendTap = [&](guint8 keycode, guint keyval, guint8 group) { - g_autoptr(FlKeyEvent) event1 = fl_key_event_new( - 0, TRUE, keycode, keyval, static_cast<GdkModifierType>(0), group); - fl_keyboard_handler_handle_event(tester.handler(), event1); - g_autoptr(FlKeyEvent) event2 = fl_key_event_new( - 0, FALSE, keycode, keyval, static_cast<GdkModifierType>(0), group); - fl_keyboard_handler_handle_event(tester.handler(), event2); - }; - - /* US keyboard layout */ - - sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA - VERIFY_DOWN(kLogicalKeyA, "a"); - - sendTap(kKeyCodeKeyA, GDK_KEY_A, 0); // Shift-KeyA - VERIFY_DOWN(kLogicalKeyA, "A"); - - sendTap(kKeyCodeDigit1, GDK_KEY_1, 0); // Digit1 - VERIFY_DOWN(kLogicalDigit1, "1"); - - sendTap(kKeyCodeDigit1, GDK_KEY_exclam, 0); // Shift-Digit1 - VERIFY_DOWN(kLogicalDigit1, "!"); - - sendTap(kKeyCodeMinus, GDK_KEY_minus, 0); // Minus - VERIFY_DOWN(kLogicalMinus, "-"); - - sendTap(kKeyCodeMinus, GDK_KEY_underscore, 0); // Shift-Minus - VERIFY_DOWN(kLogicalUnderscore, "_"); - - /* French keyboard layout, group 3, which is when the input method is showing - * "Fr" */ - - tester.setLayout(kLayoutFrench); - - sendTap(kKeyCodeKeyA, GDK_KEY_q, 3); // KeyA - VERIFY_DOWN(kLogicalKeyQ, "q"); - - sendTap(kKeyCodeKeyA, GDK_KEY_Q, 3); // Shift-KeyA - VERIFY_DOWN(kLogicalKeyQ, "Q"); - - sendTap(kKeyCodeSemicolon, GDK_KEY_m, 3); // ; but prints M - VERIFY_DOWN(kLogicalKeyM, "m"); - - sendTap(kKeyCodeKeyM, GDK_KEY_comma, 3); // M but prints , - VERIFY_DOWN(kLogicalComma, ","); - - sendTap(kKeyCodeDigit1, GDK_KEY_ampersand, 3); // Digit1 - VERIFY_DOWN(kLogicalDigit1, "&"); - - sendTap(kKeyCodeDigit1, GDK_KEY_1, 3); // Shift-Digit1 - VERIFY_DOWN(kLogicalDigit1, "1"); - - sendTap(kKeyCodeMinus, GDK_KEY_parenright, 3); // Minus - VERIFY_DOWN(kLogicalParenthesisRight, ")"); - - sendTap(kKeyCodeMinus, GDK_KEY_degree, 3); // Shift-Minus - VERIFY_DOWN(static_cast<uint32_t>(L'°'), "°"); - - /* French keyboard layout, group 0, which is pressing the "extra key for - * triggering input method" key once after switching to French IME. */ - - sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA - VERIFY_DOWN(kLogicalKeyA, "a"); - - sendTap(kKeyCodeDigit1, GDK_KEY_1, 0); // Digit1 - VERIFY_DOWN(kLogicalDigit1, "1"); - - /* Russian keyboard layout, group 2 */ - tester.setLayout(kLayoutRussian); - - sendTap(kKeyCodeKeyA, GDK_KEY_Cyrillic_ef, 2); // KeyA - VERIFY_DOWN(kLogicalKeyA, "ф"); - - sendTap(kKeyCodeDigit1, GDK_KEY_1, 2); // Shift-Digit1 - VERIFY_DOWN(kLogicalDigit1, "1"); - - sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_Cyrillic_ha, 2); - VERIFY_DOWN(kLogicalBracketLeft, "х"); - - /* Russian keyboard layout, group 0 */ - sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA - VERIFY_DOWN(kLogicalKeyA, "a"); - - sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_bracketleft, 0); - VERIFY_DOWN(kLogicalBracketLeft, "["); -} - -TEST(FlKeyboardHandlerTest, SynthesizeModifiersIfNeeded) { - KeyboardTester tester; - std::vector<CallRecord> call_records; - tester.recordEmbedderCallsTo(call_records); - - auto verifyModifierIsSynthesized = [&](GdkModifierType mask, - uint64_t physical, uint64_t logical) { - // Modifier is pressed. - guint state = mask; - fl_keyboard_handler_sync_modifier_if_needed(tester.handler(), state, 1000); - EXPECT_EQ(call_records.size(), 1u); - EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, physical, - logical, NULL, true); - // Modifier is released. - state = state ^ mask; - fl_keyboard_handler_sync_modifier_if_needed(tester.handler(), state, 1001); - EXPECT_EQ(call_records.size(), 2u); - EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeUp, physical, logical, - NULL, true); - call_records.clear(); - }; - - // No modifiers pressed. - guint state = 0; - fl_keyboard_handler_sync_modifier_if_needed(tester.handler(), state, 1000); - EXPECT_EQ(call_records.size(), 0u); - call_records.clear(); - - // Press and release each modifier once. - verifyModifierIsSynthesized(GDK_CONTROL_MASK, kPhysicalControlLeft, - kLogicalControlLeft); - verifyModifierIsSynthesized(GDK_META_MASK, kPhysicalMetaLeft, - kLogicalMetaLeft); - verifyModifierIsSynthesized(GDK_MOD1_MASK, kPhysicalAltLeft, kLogicalAltLeft); - verifyModifierIsSynthesized(GDK_SHIFT_MASK, kPhysicalShiftLeft, - kLogicalShiftLeft); -} - -TEST(FlKeyboardHandlerTest, GetPressedState) { - KeyboardTester tester; - tester.respondToTextInputWith(true); - - // Dispatch a key event. - g_autoptr(FlKeyEvent) event = fl_key_event_new( - 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); - fl_keyboard_handler_handle_event(tester.handler(), event); - - GHashTable* pressedState = - fl_keyboard_handler_get_pressed_state(tester.handler()); - EXPECT_EQ(g_hash_table_size(pressedState), 1u); - - gpointer physical_key = - g_hash_table_lookup(pressedState, uint64_to_gpointer(kPhysicalKeyA)); - EXPECT_EQ(gpointer_to_uint64(physical_key), kLogicalKeyA); -} - TEST(FlKeyboardHandlerTest, KeyboardChannelGetPressedState) { ::testing::NiceMock<flutter::testing::MockBinaryMessenger> messenger; g_autoptr(FlKeyboardHandler) handler = fl_keyboard_handler_new( - messenger, FL_KEYBOARD_VIEW_DELEGATE(fl_mock_view_delegate_new())); + messenger, + FL_KEYBOARD_VIEW_DELEGATE(fl_mock_keyboard_handler_delegate_new())); EXPECT_NE(handler, nullptr); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); @@ -1034,193 +107,3 @@ messenger.ReceiveMessage(kKeyboardChannelName, message); } - -// The following layout data is generated using DEBUG_PRINT_LAYOUT. - -const MockGroupLayoutData kLayoutUs0{{ - // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 - 0xffff, 0x0031, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08 - 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c - 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10 - 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14 - 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18 - 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c - 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20 - 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24 - 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28 - 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c - 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30 - 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34 - 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38 - 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c - 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 - 0xffff, 0xffff, 0x003c, 0x003e, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x64 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78 - 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c -}}; - -const MockGroupLayoutData kLayoutRussian0{ - // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 - 0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08 - 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c - 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10 - 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14 - 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18 - 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c - 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20 - 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24 - 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28 - 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c - 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30 - 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34 - 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38 - 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c - 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 - 0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c - 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 - 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78 - 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c -}; - -const MockGroupLayoutData kLayoutRussian2{{ - // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 - 0xffff, 0x0031, 0x0021, 0x0000, 0x0031, 0x0021, 0x0032, 0x0022, // 0x08 - 0x0033, 0x06b0, 0x0034, 0x003b, 0x0035, 0x0025, 0x0036, 0x003a, // 0x0c - 0x0037, 0x003f, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10 - 0x002d, 0x005f, 0x003d, 0x002b, 0x0071, 0x0051, 0x0000, 0x0000, // 0x14 - 0x06ca, 0x06ea, 0x06c3, 0x06e3, 0x06d5, 0x06f5, 0x06cb, 0x06eb, // 0x18 - 0x06c5, 0x06e5, 0x06ce, 0x06ee, 0x06c7, 0x06e7, 0x06db, 0x06fb, // 0x1c - 0x06dd, 0x06fd, 0x06da, 0x06fa, 0x06c8, 0x06e8, 0x06df, 0x06ff, // 0x20 - 0x0061, 0x0041, 0x0041, 0x0000, 0x06c6, 0x06e6, 0x06d9, 0x06f9, // 0x24 - 0x06d7, 0x06f7, 0x06c1, 0x06e1, 0x06d0, 0x06f0, 0x06d2, 0x06f2, // 0x28 - 0x06cf, 0x06ef, 0x06cc, 0x06ec, 0x06c4, 0x06e4, 0x06d6, 0x06f6, // 0x2c - 0x06dc, 0x06fc, 0x06a3, 0x06b3, 0x007c, 0x0000, 0x005c, 0x002f, // 0x30 - 0x06d1, 0x06f1, 0x06de, 0x06fe, 0x06d3, 0x06f3, 0x06cd, 0x06ed, // 0x34 - 0x06c9, 0x06e9, 0x06d4, 0x06f4, 0x06d8, 0x06f8, 0x06c2, 0x06e2, // 0x38 - 0x06c0, 0x06e0, 0x002e, 0x002c, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 - 0xffff, 0xffff, 0x003c, 0x003e, 0x002f, 0x007c, 0xffff, 0xffff, // 0x5c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x64 - 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0x0000, // 0x68 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, // 0x78 - 0x00b1, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x7c -}}; - -const MockGroupLayoutData kLayoutFrench0 = { - // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 - 0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08 - 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c - 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10 - 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14 - 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18 - 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c - 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20 - 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24 - 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28 - 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c - 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30 - 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34 - 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38 - 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c - 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 - 0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c - 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 - 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78 - 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c -}; - -const MockGroupLayoutData kLayoutFrench3 = { - // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 - 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 - 0x0000, 0xffff, 0x0000, 0x0000, 0x0026, 0x0031, 0x00e9, 0x0032, // 0x08 - 0x0022, 0x0033, 0x0027, 0x0034, 0x0028, 0x0035, 0x002d, 0x0036, // 0x0c - 0x00e8, 0x0037, 0x005f, 0x0038, 0x00e7, 0x0039, 0x00e0, 0x0030, // 0x10 - 0x0029, 0x00b0, 0x003d, 0x002b, 0x0000, 0x0000, 0x0061, 0x0041, // 0x14 - 0x0061, 0x0041, 0x007a, 0x005a, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18 - 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c - 0x006f, 0x004f, 0x0070, 0x0050, 0xffff, 0xffff, 0x0024, 0x00a3, // 0x20 - 0x0041, 0x0000, 0x0000, 0x0000, 0x0071, 0x0051, 0x0073, 0x0053, // 0x24 - 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28 - 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x006d, 0x004d, // 0x2c - 0x00f9, 0x0025, 0x00b2, 0x007e, 0x0000, 0x0000, 0x002a, 0x00b5, // 0x30 - 0x0077, 0x0057, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34 - 0x0062, 0x0042, 0x006e, 0x004e, 0x002c, 0x003f, 0x003b, 0x002e, // 0x38 - 0x003a, 0x002f, 0x0021, 0x00a7, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 - 0xffff, 0x003c, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c - 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68 - 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 - 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, // 0x78 - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x7c -}; - -const MockLayoutData kLayoutUs{&kLayoutUs0}; -const MockLayoutData kLayoutRussian{&kLayoutRussian0, nullptr, - &kLayoutRussian2}; -const MockLayoutData kLayoutFrench{&kLayoutFrench0, nullptr, nullptr, - &kLayoutFrench3}; - -} // namespace
diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc new file mode 100644 index 0000000..3c0b8f1 --- /dev/null +++ b/shell/platform/linux/fl_keyboard_manager.cc
@@ -0,0 +1,510 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" + +#include <array> +#include <cinttypes> +#include <memory> +#include <string> + +#include "flutter/shell/platform/linux/fl_key_channel_responder.h" +#include "flutter/shell/platform/linux/fl_key_embedder_responder.h" +#include "flutter/shell/platform/linux/fl_keyboard_layout.h" +#include "flutter/shell/platform/linux/fl_keyboard_pending_event.h" +#include "flutter/shell/platform/linux/key_mapping.h" + +// Turn on this flag to print complete layout data when switching IMEs. The data +// is used in unit tests. +#define DEBUG_PRINT_LAYOUT + +/* Declarations of private classes */ + +G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData, + fl_keyboard_manager_user_data, + FL, + KEYBOARD_MANAGER_USER_DATA, + GObject); + +/* End declarations */ + +namespace { + +static bool is_eascii(uint16_t character) { + return character < 256; +} + +#ifdef DEBUG_PRINT_LAYOUT +// Prints layout entries that will be parsed by `MockLayoutData`. +void debug_format_layout_data(std::string& debug_layout_data, + uint16_t keycode, + uint16_t clue1, + uint16_t clue2) { + if (keycode % 4 == 0) { + debug_layout_data.append(" "); + } + + constexpr int kBufferSize = 30; + char buffer[kBufferSize]; + buffer[0] = 0; + buffer[kBufferSize - 1] = 0; + + snprintf(buffer, kBufferSize, "0x%04x, 0x%04x, ", clue1, clue2); + debug_layout_data.append(buffer); + + if (keycode % 4 == 3) { + snprintf(buffer, kBufferSize, " // 0x%02x", keycode); + debug_layout_data.append(buffer); + } +} +#endif + +} // namespace + +/* Define FlKeyboardManagerUserData */ + +/** + * FlKeyboardManagerUserData: + * The user_data used when #FlKeyboardManager sends event to + * responders. + */ + +struct _FlKeyboardManagerUserData { + GObject parent_instance; + + // The owner manager. + GWeakRef manager; + uint64_t sequence_id; +}; + +G_DEFINE_TYPE(FlKeyboardManagerUserData, + fl_keyboard_manager_user_data, + G_TYPE_OBJECT) + +static void fl_keyboard_manager_user_data_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(object)); + FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(object); + + g_weak_ref_clear(&self->manager); + + G_OBJECT_CLASS(fl_keyboard_manager_user_data_parent_class)->dispose(object); +} + +static void fl_keyboard_manager_user_data_class_init( + FlKeyboardManagerUserDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_user_data_dispose; +} + +static void fl_keyboard_manager_user_data_init( + FlKeyboardManagerUserData* self) {} + +// Creates a new FlKeyboardManagerUserData private class with all information. +static FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new( + FlKeyboardManager* manager, + uint64_t sequence_id) { + FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA( + g_object_new(fl_keyboard_manager_user_data_get_type(), nullptr)); + + g_weak_ref_init(&self->manager, manager); + self->sequence_id = sequence_id; + return self; +} + +/* Define FlKeyboardManager */ + +struct _FlKeyboardManager { + GObject parent_instance; + + GWeakRef view_delegate; + + // An array of #FlKeyResponder. Elements are added with + // #fl_keyboard_manager_add_responder immediately after initialization and are + // automatically released on dispose. + GPtrArray* responder_list; + + // An array of #FlKeyboardPendingEvent. + // + // Its elements are *not* unreferenced when removed. When FlKeyboardManager is + // disposed, this array will be set with a free_func so that the elements are + // unreferenced when removed. + GPtrArray* pending_responds; + + // An array of #FlKeyboardPendingEvent. + // + // Its elements are unreferenced when removed. + GPtrArray* pending_redispatches; + + // The last sequence ID used. Increased by 1 by every use. + uint64_t last_sequence_id; + + // Record the derived layout. + // + // It is cleared when the platform reports a layout switch. Each entry, + // which corresponds to a group, is only initialized on the arrival of the + // first event for that group that has a goal keycode. + FlKeyboardLayout* derived_layout; + + // A static map from keycodes to all layout goals. + // + // It is set up when the manager is initialized and is not changed ever after. + std::unique_ptr<std::map<uint16_t, const LayoutGoal*>> keycode_to_goals; + + // A static map from logical keys to all mandatory layout goals. + // + // It is set up when the manager is initialized and is not changed ever after. + std::unique_ptr<std::map<uint64_t, const LayoutGoal*>> + logical_to_mandatory_goals; +}; + +G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT); + +// This is an exact copy of g_ptr_array_find_with_equal_func. Somehow CI +// reports that can not find symbol g_ptr_array_find_with_equal_func, despite +// the fact that it runs well locally. +static gboolean g_ptr_array_find_with_equal_func1(GPtrArray* haystack, + gconstpointer needle, + GEqualFunc equal_func, + guint* index_) { + guint i; + g_return_val_if_fail(haystack != NULL, FALSE); + if (equal_func == NULL) { + equal_func = g_direct_equal; + } + for (i = 0; i < haystack->len; i++) { + if (equal_func(g_ptr_array_index(haystack, i), needle)) { + if (index_ != NULL) { + *index_ = i; + } + return TRUE; + } + } + + return FALSE; +} + +// Compare a #FlKeyboardPendingEvent with the given sequence_id. +static gboolean compare_pending_by_sequence_id(gconstpointer a, + gconstpointer b) { + FlKeyboardPendingEvent* pending = + FL_KEYBOARD_PENDING_EVENT(const_cast<gpointer>(a)); + uint64_t sequence_id = *reinterpret_cast<const uint64_t*>(b); + return fl_keyboard_pending_event_get_sequence_id(pending) == sequence_id; +} + +// Compare a #FlKeyboardPendingEvent with the given hash. +static gboolean compare_pending_by_hash(gconstpointer a, gconstpointer b) { + FlKeyboardPendingEvent* pending = + FL_KEYBOARD_PENDING_EVENT(const_cast<gpointer>(a)); + uint64_t hash = *reinterpret_cast<const uint64_t*>(b); + return fl_keyboard_pending_event_get_hash(pending) == hash; +} + +// Try to remove a pending event from `pending_redispatches` with the target +// hash. +// +// Returns true if the event is found and removed. +static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, + uint64_t hash) { + guint result_index; + gboolean found = g_ptr_array_find_with_equal_func1( + self->pending_redispatches, static_cast<const uint64_t*>(&hash), + compare_pending_by_hash, &result_index); + if (found) { + // The removed object is freed due to `pending_redispatches`'s free_func. + g_ptr_array_remove_index_fast(self->pending_redispatches, result_index); + return TRUE; + } else { + return FALSE; + } +} + +// The callback used by a responder after the event was dispatched. +static void responder_handle_event_callback(bool handled, + gpointer user_data_ptr) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr)); + FlKeyboardManagerUserData* user_data = + FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr); + + g_autoptr(FlKeyboardManager) self = + FL_KEYBOARD_MANAGER(g_weak_ref_get(&user_data->manager)); + if (self == nullptr) { + return; + } + + g_autoptr(FlKeyboardViewDelegate) view_delegate = + FL_KEYBOARD_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate)); + if (view_delegate == nullptr) { + return; + } + + guint result_index = -1; + gboolean found = g_ptr_array_find_with_equal_func1( + self->pending_responds, &user_data->sequence_id, + compare_pending_by_sequence_id, &result_index); + g_return_if_fail(found); + FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT( + g_ptr_array_index(self->pending_responds, result_index)); + g_return_if_fail(pending != nullptr); + fl_keyboard_pending_event_mark_replied(pending, handled); + // All responders have replied. + if (fl_keyboard_pending_event_is_complete(pending)) { + g_object_unref(user_data_ptr); + gpointer removed = + g_ptr_array_remove_index_fast(self->pending_responds, result_index); + g_return_if_fail(removed == pending); + bool should_redispatch = + !fl_keyboard_pending_event_get_any_handled(pending) && + !fl_keyboard_view_delegate_text_filter_key_press( + view_delegate, fl_keyboard_pending_event_get_event(pending)); + if (should_redispatch) { + g_ptr_array_add(self->pending_redispatches, pending); + fl_keyboard_view_delegate_redispatch_event( + view_delegate, + FL_KEY_EVENT(fl_keyboard_pending_event_get_event(pending))); + } else { + g_object_unref(pending); + } + } +} + +static uint16_t convert_key_to_char(FlKeyboardViewDelegate* view_delegate, + guint keycode, + gint group, + gint level) { + GdkKeymapKey key = {keycode, group, level}; + constexpr int kBmpMax = 0xD7FF; + guint origin = fl_keyboard_view_delegate_lookup_key(view_delegate, &key); + return origin < kBmpMax ? origin : 0xFFFF; +} + +// Make sure that Flutter has derived the layout for the group of the event, +// if the event contains a goal keycode. +static void guarantee_layout(FlKeyboardManager* self, FlKeyEvent* event) { + g_autoptr(FlKeyboardViewDelegate) view_delegate = + FL_KEYBOARD_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate)); + if (view_delegate == nullptr) { + return; + } + + guint8 group = fl_key_event_get_group(event); + if (fl_keyboard_layout_has_group(self->derived_layout, group)) { + return; + } + if (self->keycode_to_goals->find(fl_key_event_get_keycode(event)) == + self->keycode_to_goals->end()) { + return; + } + + // Clone all mandatory goals. Each goal is removed from this cloned map when + // fulfilled, and the remaining ones will be assigned to a default position. + std::map<uint64_t, const LayoutGoal*> remaining_mandatory_goals = + *self->logical_to_mandatory_goals; + +#ifdef DEBUG_PRINT_LAYOUT + std::string debug_layout_data; + for (uint16_t keycode = 0; keycode < 128; keycode += 1) { + std::vector<uint16_t> this_key_clues = { + convert_key_to_char(view_delegate, keycode, group, 0), + convert_key_to_char(view_delegate, keycode, group, 1), // Shift + }; + debug_format_layout_data(debug_layout_data, keycode, this_key_clues[0], + this_key_clues[1]); + } +#endif + + // It's important to only traverse layout goals instead of all keycodes. + // Some key codes outside of the standard keyboard also gives alpha-numeric + // letters, and will therefore take over mandatory goals from standard + // keyboard keys if they come first. Example: French keyboard digit 1. + for (const LayoutGoal& keycode_goal : layout_goals) { + uint16_t keycode = keycode_goal.keycode; + std::vector<uint16_t> this_key_clues = { + convert_key_to_char(view_delegate, keycode, group, 0), + convert_key_to_char(view_delegate, keycode, group, 1), // Shift + }; + + // The logical key should be the first available clue from below: + // + // - Mandatory goal, if it matches any clue. This ensures that all alnum + // keys can be found somewhere. + // - US layout, if neither clue of the key is EASCII. This ensures that + // there are no non-latin logical keys. + // - A value derived on the fly from keycode & keyval. + for (uint16_t clue : this_key_clues) { + auto matching_goal = remaining_mandatory_goals.find(clue); + if (matching_goal != remaining_mandatory_goals.end()) { + // Found a key that produces a mandatory char. Use it. + g_return_if_fail(fl_keyboard_layout_get_logical_key( + self->derived_layout, group, keycode) == 0); + fl_keyboard_layout_set_logical_key(self->derived_layout, group, keycode, + clue); + remaining_mandatory_goals.erase(matching_goal); + break; + } + } + bool has_any_eascii = + is_eascii(this_key_clues[0]) || is_eascii(this_key_clues[1]); + // See if any produced char meets the requirement as a logical key. + if (fl_keyboard_layout_get_logical_key(self->derived_layout, group, + keycode) == 0 && + !has_any_eascii) { + auto found_us_layout = self->keycode_to_goals->find(keycode); + if (found_us_layout != self->keycode_to_goals->end()) { + fl_keyboard_layout_set_logical_key( + self->derived_layout, group, keycode, + found_us_layout->second->logical_key); + } + } + } + + // Ensure all mandatory goals are assigned. + for (const auto mandatory_goal_iter : remaining_mandatory_goals) { + const LayoutGoal* goal = mandatory_goal_iter.second; + fl_keyboard_layout_set_logical_key(self->derived_layout, group, + goal->keycode, goal->logical_key); + } +} + +static void fl_keyboard_manager_dispose(GObject* object) { + FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object); + + g_weak_ref_clear(&self->view_delegate); + + self->keycode_to_goals.reset(); + self->logical_to_mandatory_goals.reset(); + + g_ptr_array_free(self->responder_list, TRUE); + g_ptr_array_set_free_func(self->pending_responds, g_object_unref); + g_ptr_array_free(self->pending_responds, TRUE); + g_ptr_array_free(self->pending_redispatches, TRUE); + g_clear_object(&self->derived_layout); + + G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object); +} + +static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose; +} + +static void fl_keyboard_manager_init(FlKeyboardManager* self) { + self->derived_layout = fl_keyboard_layout_new(); + + self->keycode_to_goals = + std::make_unique<std::map<uint16_t, const LayoutGoal*>>(); + self->logical_to_mandatory_goals = + std::make_unique<std::map<uint64_t, const LayoutGoal*>>(); + for (const LayoutGoal& goal : layout_goals) { + (*self->keycode_to_goals)[goal.keycode] = &goal; + if (goal.mandatory) { + (*self->logical_to_mandatory_goals)[goal.logical_key] = &goal; + } + } + + self->responder_list = g_ptr_array_new_with_free_func(g_object_unref); + + self->pending_responds = g_ptr_array_new(); + self->pending_redispatches = g_ptr_array_new_with_free_func(g_object_unref); + + self->last_sequence_id = 1; +} + +FlKeyboardManager* fl_keyboard_manager_new( + FlBinaryMessenger* messenger, + FlKeyboardViewDelegate* view_delegate) { + g_return_val_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(view_delegate), nullptr); + + FlKeyboardManager* self = FL_KEYBOARD_MANAGER( + g_object_new(fl_keyboard_manager_get_type(), nullptr)); + + g_weak_ref_init(&self->view_delegate, view_delegate); + + // The embedder responder must be added before the channel responder. + g_ptr_array_add( + self->responder_list, + FL_KEY_RESPONDER(fl_key_embedder_responder_new( + [](const FlutterKeyEvent* event, FlutterKeyEventCallback callback, + void* callback_user_data, void* send_key_event_user_data) { + FlKeyboardManager* self = + FL_KEYBOARD_MANAGER(send_key_event_user_data); + g_autoptr(FlKeyboardViewDelegate) view_delegate = + FL_KEYBOARD_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate)); + if (view_delegate == nullptr) { + return; + } + fl_keyboard_view_delegate_send_key_event( + view_delegate, event, callback, callback_user_data); + }, + self))); + g_ptr_array_add(self->responder_list, + FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger))); + + return self; +} + +gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, + FlKeyEvent* event) { + g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); + g_return_val_if_fail(event != nullptr, FALSE); + + guarantee_layout(self, event); + + uint64_t incoming_hash = fl_key_event_hash(event); + if (fl_keyboard_manager_remove_redispatched(self, incoming_hash)) { + return FALSE; + } + + FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( + event, ++self->last_sequence_id, self->responder_list->len); + + g_ptr_array_add(self->pending_responds, pending); + FlKeyboardManagerUserData* user_data = fl_keyboard_manager_user_data_new( + self, fl_keyboard_pending_event_get_sequence_id(pending)); + uint64_t specified_logical_key = fl_keyboard_layout_get_logical_key( + self->derived_layout, fl_key_event_get_group(event), + fl_key_event_get_keycode(event)); + for (guint i = 0; i < self->responder_list->len; i++) { + FlKeyResponder* responder = + FL_KEY_RESPONDER(g_ptr_array_index(self->responder_list, i)); + fl_key_responder_handle_event(responder, event, + responder_handle_event_callback, user_data, + specified_logical_key); + } + + return TRUE; +} + +gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); + return self->pending_responds->len == 0 && + self->pending_redispatches->len == 0; +} + +void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* self, + guint state, + double event_time) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self)); + + // The embedder responder is the first element in + // FlKeyboardManager.responder_list. + FlKeyEmbedderResponder* responder = + FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0)); + fl_key_embedder_responder_sync_modifiers_if_needed(responder, state, + event_time); +} + +GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), nullptr); + + // The embedder responder is the first element in + // FlKeyboardManager.responder_list. + FlKeyEmbedderResponder* responder = + FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0)); + return fl_key_embedder_responder_get_pressed_state(responder); +} + +void fl_keyboard_manager_notify_layout_changed(FlKeyboardManager* self) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self)); + g_clear_object(&self->derived_layout); + self->derived_layout = fl_keyboard_layout_new(); +}
diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h new file mode 100644 index 0000000..383c7f9 --- /dev/null +++ b/shell/platform/linux/fl_keyboard_manager.h
@@ -0,0 +1,108 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_ + +#include <gdk/gdk.h> + +#include "flutter/shell/platform/linux/fl_keyboard_view_delegate.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" + +G_BEGIN_DECLS + +#define FL_TYPE_KEYBOARD_MANAGER fl_keyboard_manager_get_type() +G_DECLARE_FINAL_TYPE(FlKeyboardManager, + fl_keyboard_manager, + FL, + KEYBOARD_MANAGER, + GObject); + +/** + * FlKeyboardManager: + * + * Processes keyboard events and cooperate with `TextInputManager`. + * + * A keyboard event goes through a few sections, each can choose to handle the + * event, and only unhandled events can move to the next section: + * + * - Keyboard: Dispatch to the embedder responder and the channel responder + * simultaneously. After both responders have responded (asynchronously), the + * event is considered handled if either responder handles it. + * - Text input: Events are sent to IM filter (usually owned by + * `TextInputManager`) and are handled synchronously. + * - Redispatching: Events are inserted back to the system for redispatching. + */ + +/** + * fl_keyboard_manager_new: + * @messenger: an #FlBinaryMessenger. + * @view_delegate: An interface that the manager requires to communicate with + * the platform. Usually implemented by FlView. + * + * Create a new #FlKeyboardManager. + * + * Returns: a new #FlKeyboardManager. + */ +FlKeyboardManager* fl_keyboard_manager_new( + FlBinaryMessenger* messenger, + FlKeyboardViewDelegate* view_delegate); + +/** + * fl_keyboard_manager_handle_event: + * @manager: the #FlKeyboardManager self. + * @event: the event to be dispatched. It is usually a wrap of a GdkEventKey. + * This event will be managed and released by #FlKeyboardManager. + * + * Make the manager process a system key event. This might eventually send + * messages to the framework, trigger text input effects, or redispatch the + * event back to the system. + */ +gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, + FlKeyEvent* event); + +/** + * fl_keyboard_manager_is_state_clear: + * @manager: the #FlKeyboardManager self. + * + * A debug-only method that queries whether the manager's various states are + * cleared, i.e. no pending events for redispatching or for responding. + * + * Returns: true if the manager's various states are cleared. + */ +gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* manager); + +/** + * fl_keyboard_manager_sync_modifier_if_needed: + * @manager: the #FlKeyboardManager self. + * @state: the state of the modifiers mask. + * @event_time: the time attribute of the incoming GDK event. + * + * If needed, synthesize modifier keys up and down event by comparing their + * current pressing states with the given modifiers mask. + */ +void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* manager, + guint state, + double event_time); + +/** + * fl_keyboard_manager_get_pressed_state: + * @manager: the #FlKeyboardManager self. + * + * Returns the keyboard pressed state. The hash table contains one entry per + * pressed keys, mapping from the logical key to the physical key.* + */ +GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* manager); + +/** + * fl_keyboard_manager_notify_layout_changed: + * @manager: the #FlKeyboardManager self. + * + * Notify the manager the keyboard layout has changed. + */ +void fl_keyboard_manager_notify_layout_changed(FlKeyboardManager* manager); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_
diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc new file mode 100644 index 0000000..d655df3 --- /dev/null +++ b/shell/platform/linux/fl_keyboard_manager_test.cc
@@ -0,0 +1,1139 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" + +#include <cstring> +#include <vector> + +#include "flutter/shell/platform/embedder/test_utils/key_codes.g.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" +#include "flutter/shell/platform/linux/fl_method_codec_private.h" +#include "flutter/shell/platform/linux/key_mapping.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" +#include "flutter/shell/platform/linux/testing/mock_text_input_handler.h" +#include "flutter/testing/testing.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +// Define compound `expect` in macros. If they were defined in functions, the +// stacktrace wouldn't print where the function is called in the unit tests. + +#define EXPECT_KEY_EVENT(RECORD, TYPE, PHYSICAL, LOGICAL, CHAR, SYNTHESIZED) \ + EXPECT_EQ((RECORD).type, CallRecord::kKeyCallEmbedder); \ + EXPECT_EQ((RECORD).event->type, (TYPE)); \ + EXPECT_EQ((RECORD).event->physical, (PHYSICAL)); \ + EXPECT_EQ((RECORD).event->logical, (LOGICAL)); \ + EXPECT_STREQ((RECORD).event->character, (CHAR)); \ + EXPECT_EQ((RECORD).event->synthesized, (SYNTHESIZED)); + +#define VERIFY_DOWN(OUT_LOGICAL, OUT_CHAR) \ + EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); \ + EXPECT_EQ(call_records[0].event->type, kFlutterKeyEventTypeDown); \ + EXPECT_EQ(call_records[0].event->logical, (OUT_LOGICAL)); \ + EXPECT_STREQ(call_records[0].event->character, (OUT_CHAR)); \ + EXPECT_EQ(call_records[0].event->synthesized, false); \ + call_records.clear() + +namespace { +using ::flutter::testing::keycodes::kLogicalAltLeft; +using ::flutter::testing::keycodes::kLogicalBracketLeft; +using ::flutter::testing::keycodes::kLogicalComma; +using ::flutter::testing::keycodes::kLogicalControlLeft; +using ::flutter::testing::keycodes::kLogicalDigit1; +using ::flutter::testing::keycodes::kLogicalKeyA; +using ::flutter::testing::keycodes::kLogicalKeyB; +using ::flutter::testing::keycodes::kLogicalKeyM; +using ::flutter::testing::keycodes::kLogicalKeyQ; +using ::flutter::testing::keycodes::kLogicalMetaLeft; +using ::flutter::testing::keycodes::kLogicalMinus; +using ::flutter::testing::keycodes::kLogicalParenthesisRight; +using ::flutter::testing::keycodes::kLogicalSemicolon; +using ::flutter::testing::keycodes::kLogicalShiftLeft; +using ::flutter::testing::keycodes::kLogicalUnderscore; + +using ::flutter::testing::keycodes::kPhysicalAltLeft; +using ::flutter::testing::keycodes::kPhysicalControlLeft; +using ::flutter::testing::keycodes::kPhysicalKeyA; +using ::flutter::testing::keycodes::kPhysicalKeyB; +using ::flutter::testing::keycodes::kPhysicalMetaLeft; +using ::flutter::testing::keycodes::kPhysicalShiftLeft; + +// Hardware key codes. +typedef std::function<void(bool handled)> AsyncKeyCallback; +typedef std::function<void(AsyncKeyCallback callback)> ChannelCallHandler; +typedef std::function<void(const FlutterKeyEvent* event, + AsyncKeyCallback callback)> + EmbedderCallHandler; +typedef std::function<void(FlKeyEvent*)> RedispatchHandler; + +// A type that can record all kinds of effects that the keyboard handler +// triggers. +// +// An instance of `CallRecord` might not have all the fields filled. +typedef struct { + enum { + kKeyCallEmbedder, + kKeyCallChannel, + } type; + + AsyncKeyCallback callback; + std::unique_ptr<FlutterKeyEvent> event; + std::unique_ptr<char[]> event_character; +} CallRecord; + +// Clone a C-string. +// +// Must be deleted by delete[]. +char* cloneString(const char* source) { + if (source == nullptr) { + return nullptr; + } + size_t charLen = strlen(source); + char* target = new char[charLen + 1]; + strncpy(target, source, charLen + 1); + return target; +} + +constexpr guint16 kKeyCodeKeyA = 0x26u; +constexpr guint16 kKeyCodeKeyB = 0x38u; +constexpr guint16 kKeyCodeKeyM = 0x3au; +constexpr guint16 kKeyCodeDigit1 = 0x0au; +constexpr guint16 kKeyCodeMinus = 0x14u; +constexpr guint16 kKeyCodeSemicolon = 0x2fu; +constexpr guint16 kKeyCodeKeyLeftBracket = 0x22u; + +static constexpr char kKeyEventChannelName[] = "flutter/keyevent"; + +// All key clues for a keyboard layout. +// +// The index is (keyCode * 2 + hasShift), where each value is the character for +// this key (GTK only supports UTF-16.) Since the maximum keycode of interest +// is 128, it has a total of 256 entries.. +typedef std::array<uint32_t, 256> MockGroupLayoutData; +typedef std::vector<const MockGroupLayoutData*> MockLayoutData; + +extern const MockLayoutData kLayoutUs; +extern const MockLayoutData kLayoutRussian; +extern const MockLayoutData kLayoutFrench; + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlMockViewDelegate, + fl_mock_view_delegate, + FL, + MOCK_VIEW_DELEGATE, + GObject); + +G_DECLARE_FINAL_TYPE(FlMockKeyBinaryMessenger, + fl_mock_key_binary_messenger, + FL, + MOCK_KEY_BINARY_MESSENGER, + GObject) + +G_END_DECLS + +MATCHER_P(MethodSuccessResponse, result, "") { + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodResponse) response = + fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); + fl_method_response_get_result(response, nullptr); + if (fl_value_equal(fl_method_response_get_result(response, nullptr), + result)) { + return true; + } + *result_listener << ::testing::PrintToString(response); + return false; +} + +/***** FlMockKeyBinaryMessenger *****/ +/* Mock a binary messenger that only processes messages from the embedding on + * the key event channel, and does so according to the callback set by + * fl_mock_key_binary_messenger_set_callback_handler */ + +struct _FlMockKeyBinaryMessenger { + GObject parent_instance; + + ChannelCallHandler callback_handler; +}; + +static void fl_mock_key_binary_messenger_iface_init( + FlBinaryMessengerInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlMockKeyBinaryMessenger, + fl_mock_key_binary_messenger, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_binary_messenger_get_type(), + fl_mock_key_binary_messenger_iface_init)) + +static void fl_mock_key_binary_messenger_init(FlMockKeyBinaryMessenger* self) {} + +static void fl_mock_key_binary_messenger_dispose(GObject* object) { + G_OBJECT_CLASS(fl_mock_key_binary_messenger_parent_class)->dispose(object); +} + +static void fl_mock_key_binary_messenger_class_init( + FlMockKeyBinaryMessengerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_mock_key_binary_messenger_dispose; +} + +static void fl_mock_key_binary_messenger_send_on_channel( + FlBinaryMessenger* messenger, + const gchar* channel, + GBytes* message, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + FlMockKeyBinaryMessenger* self = FL_MOCK_KEY_BINARY_MESSENGER(messenger); + + if (callback != nullptr) { + EXPECT_STREQ(channel, kKeyEventChannelName); + self->callback_handler([self, cancellable, callback, + user_data](bool handled) { + g_autoptr(GTask) task = + g_task_new(self, cancellable, callback, user_data); + g_autoptr(FlValue) result = fl_value_new_map(); + fl_value_set_string_take(result, "handled", fl_value_new_bool(handled)); + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + g_autoptr(GError) error = nullptr; + GBytes* data = fl_message_codec_encode_message(FL_MESSAGE_CODEC(codec), + result, &error); + + g_task_return_pointer(task, data, + reinterpret_cast<GDestroyNotify>(g_bytes_unref)); + }); + } +} + +static GBytes* fl_mock_key_binary_messenger_send_on_channel_finish( + FlBinaryMessenger* messenger, + GAsyncResult* result, + GError** error) { + return static_cast<GBytes*>(g_task_propagate_pointer(G_TASK(result), error)); +} + +static void fl_mock_binary_messenger_resize_channel( + FlBinaryMessenger* messenger, + const gchar* channel, + int64_t new_size) { + // Mock implementation. Do nothing. +} + +static void fl_mock_binary_messenger_set_warns_on_channel_overflow( + FlBinaryMessenger* messenger, + const gchar* channel, + bool warns) { + // Mock implementation. Do nothing. +} + +static void fl_mock_key_binary_messenger_iface_init( + FlBinaryMessengerInterface* iface) { + iface->set_message_handler_on_channel = + [](FlBinaryMessenger* messenger, const gchar* channel, + FlBinaryMessengerMessageHandler handler, gpointer user_data, + GDestroyNotify destroy_notify) { + EXPECT_STREQ(channel, kKeyEventChannelName); + // No need to mock. The key event channel expects no incoming messages + // from the framework. + }; + iface->send_response = [](FlBinaryMessenger* messenger, + FlBinaryMessengerResponseHandle* response_handle, + GBytes* response, GError** error) -> gboolean { + // The key event channel expects no incoming messages from the framework, + // hence no responses either. + g_return_val_if_reached(TRUE); + return TRUE; + }; + iface->send_on_channel = fl_mock_key_binary_messenger_send_on_channel; + iface->send_on_channel_finish = + fl_mock_key_binary_messenger_send_on_channel_finish; + iface->resize_channel = fl_mock_binary_messenger_resize_channel; + iface->set_warns_on_channel_overflow = + fl_mock_binary_messenger_set_warns_on_channel_overflow; +} + +static FlMockKeyBinaryMessenger* fl_mock_key_binary_messenger_new() { + FlMockKeyBinaryMessenger* self = FL_MOCK_KEY_BINARY_MESSENGER( + g_object_new(fl_mock_key_binary_messenger_get_type(), NULL)); + + // Added to stop compiler complaining about an unused function. + FL_IS_MOCK_KEY_BINARY_MESSENGER(self); + + return self; +} + +static void fl_mock_key_binary_messenger_set_callback_handler( + FlMockKeyBinaryMessenger* self, + ChannelCallHandler handler) { + self->callback_handler = std::move(handler); +} + +/***** FlMockViewDelegate *****/ + +struct _FlMockViewDelegate { + GObject parent_instance; + + FlMockKeyBinaryMessenger* messenger; + EmbedderCallHandler embedder_handler; + bool text_filter_result; + RedispatchHandler redispatch_handler; + const MockLayoutData* layout_data; +}; + +static void fl_mock_view_keyboard_delegate_iface_init( + FlKeyboardViewDelegateInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlMockViewDelegate, + fl_mock_view_delegate, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(), + fl_mock_view_keyboard_delegate_iface_init)) + +static void fl_mock_view_delegate_init(FlMockViewDelegate* self) {} + +static void fl_mock_view_delegate_dispose(GObject* object) { + FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(object); + + g_clear_object(&self->messenger); + + G_OBJECT_CLASS(fl_mock_view_delegate_parent_class)->dispose(object); +} + +static void fl_mock_view_delegate_class_init(FlMockViewDelegateClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_mock_view_delegate_dispose; +} + +static void fl_mock_view_keyboard_send_key_event( + FlKeyboardViewDelegate* view_delegate, + const FlutterKeyEvent* event, + FlutterKeyEventCallback callback, + void* user_data) { + FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(view_delegate); + self->embedder_handler(event, [callback, user_data](bool handled) { + if (callback != nullptr) { + callback(handled, user_data); + } + }); +} + +static gboolean fl_mock_view_keyboard_text_filter_key_press( + FlKeyboardViewDelegate* view_delegate, + FlKeyEvent* event) { + FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(view_delegate); + return self->text_filter_result; +} + +static void fl_mock_view_keyboard_redispatch_event( + FlKeyboardViewDelegate* view_delegate, + FlKeyEvent* event) { + FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(view_delegate); + if (self->redispatch_handler) { + self->redispatch_handler(event); + } +} + +static guint fl_mock_view_keyboard_lookup_key( + FlKeyboardViewDelegate* view_delegate, + const GdkKeymapKey* key) { + FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(view_delegate); + guint8 group = static_cast<guint8>(key->group); + EXPECT_LT(group, self->layout_data->size()); + const MockGroupLayoutData* group_layout = (*self->layout_data)[group]; + EXPECT_TRUE(group_layout != nullptr); + EXPECT_TRUE(key->level == 0 || key->level == 1); + bool shift = key->level == 1; + return (*group_layout)[key->keycode * 2 + shift]; +} + +static void fl_mock_view_keyboard_delegate_iface_init( + FlKeyboardViewDelegateInterface* iface) { + iface->send_key_event = fl_mock_view_keyboard_send_key_event; + iface->text_filter_key_press = fl_mock_view_keyboard_text_filter_key_press; + iface->redispatch_event = fl_mock_view_keyboard_redispatch_event; + iface->lookup_key = fl_mock_view_keyboard_lookup_key; +} + +static FlMockViewDelegate* fl_mock_view_delegate_new() { + FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE( + g_object_new(fl_mock_view_delegate_get_type(), nullptr)); + + // Added to stop compiler complaining about an unused function. + FL_IS_MOCK_VIEW_DELEGATE(self); + + self->messenger = fl_mock_key_binary_messenger_new(); + + return self; +} + +static void fl_mock_view_set_embedder_handler(FlMockViewDelegate* self, + EmbedderCallHandler handler) { + self->embedder_handler = std::move(handler); +} + +static void fl_mock_view_set_text_filter_result(FlMockViewDelegate* self, + bool result) { + self->text_filter_result = result; +} + +static void fl_mock_view_set_redispatch_handler(FlMockViewDelegate* self, + RedispatchHandler handler) { + self->redispatch_handler = std::move(handler); +} + +static void fl_mock_view_set_layout(FlMockViewDelegate* self, + const MockLayoutData* layout) { + self->layout_data = layout; +} + +/***** End FlMockViewDelegate *****/ + +class KeyboardTester { + public: + KeyboardTester() { + view_ = fl_mock_view_delegate_new(); + respondToEmbedderCallsWith(false); + respondToChannelCallsWith(false); + respondToTextInputWith(false); + setLayout(kLayoutUs); + + handler_ = fl_keyboard_manager_new(FL_BINARY_MESSENGER(view_->messenger), + FL_KEYBOARD_VIEW_DELEGATE(view_)); + } + + ~KeyboardTester() { + g_clear_object(&view_); + g_clear_object(&handler_); + g_clear_pointer(&redispatched_events_, g_ptr_array_unref); + } + + FlKeyboardManager* handler() { return handler_; } + + // Block until all GdkMainLoop messages are processed, which is basically + // used only for channel messages. + void flushChannelMessages() { + GMainLoop* loop = g_main_loop_new(nullptr, 0); + g_idle_add(_flushChannelMessagesCb, loop); + g_main_loop_run(loop); + } + + // Dispatch each of the given events, expect their results to be false + // (unhandled), and clear the event array. + // + // Returns the number of events redispatched. If any result is unexpected + // (handled), return a minus number `-x` instead, where `x` is the index of + // the first unexpected redispatch. + int redispatchEventsAndClear(GPtrArray* events) { + guint event_count = events->len; + int first_error = -1; + during_redispatch_ = true; + for (guint event_id = 0; event_id < event_count; event_id += 1) { + FlKeyEvent* event = FL_KEY_EVENT(g_ptr_array_index(events, event_id)); + bool handled = fl_keyboard_manager_handle_event(handler_, event); + EXPECT_FALSE(handled); + if (handled) { + first_error = first_error == -1 ? event_id : first_error; + } + } + during_redispatch_ = false; + g_ptr_array_set_size(events, 0); + return first_error < 0 ? event_count : -first_error; + } + + void respondToEmbedderCallsWith(bool response) { + fl_mock_view_set_embedder_handler( + view_, [response, this](const FlutterKeyEvent* event, + const AsyncKeyCallback& callback) { + EXPECT_FALSE(during_redispatch_); + callback(response); + }); + } + + void recordEmbedderCallsTo(std::vector<CallRecord>& storage) { + fl_mock_view_set_embedder_handler( + view_, [&storage, this](const FlutterKeyEvent* event, + AsyncKeyCallback callback) { + EXPECT_FALSE(during_redispatch_); + auto new_event = std::make_unique<FlutterKeyEvent>(*event); + char* new_event_character = cloneString(event->character); + new_event->character = new_event_character; + storage.push_back(CallRecord{ + .type = CallRecord::kKeyCallEmbedder, + .callback = std::move(callback), + .event = std::move(new_event), + .event_character = std::unique_ptr<char[]>(new_event_character), + }); + }); + } + + void respondToEmbedderCallsWithAndRecordsTo( + bool response, + std::vector<CallRecord>& storage) { + fl_mock_view_set_embedder_handler( + view_, [&storage, response, this](const FlutterKeyEvent* event, + const AsyncKeyCallback& callback) { + EXPECT_FALSE(during_redispatch_); + auto new_event = std::make_unique<FlutterKeyEvent>(*event); + char* new_event_character = cloneString(event->character); + new_event->character = new_event_character; + storage.push_back(CallRecord{ + .type = CallRecord::kKeyCallEmbedder, + .event = std::move(new_event), + .event_character = std::unique_ptr<char[]>(new_event_character), + }); + callback(response); + }); + } + + void respondToChannelCallsWith(bool response) { + fl_mock_key_binary_messenger_set_callback_handler( + view_->messenger, [response, this](const AsyncKeyCallback& callback) { + EXPECT_FALSE(during_redispatch_); + callback(response); + }); + } + + void recordChannelCallsTo(std::vector<CallRecord>& storage) { + fl_mock_key_binary_messenger_set_callback_handler( + view_->messenger, [&storage, this](AsyncKeyCallback callback) { + EXPECT_FALSE(during_redispatch_); + storage.push_back(CallRecord{ + .type = CallRecord::kKeyCallChannel, + .callback = std::move(callback), + }); + }); + } + + void respondToTextInputWith(bool response) { + fl_mock_view_set_text_filter_result(view_, response); + } + + void recordRedispatchedEventsTo(GPtrArray* storage) { + redispatched_events_ = g_ptr_array_ref(storage); + fl_mock_view_set_redispatch_handler(view_, [this](FlKeyEvent* key) { + g_ptr_array_add(redispatched_events_, g_object_ref(key)); + }); + } + + void setLayout(const MockLayoutData& layout) { + fl_mock_view_set_layout(view_, &layout); + if (handler_ != nullptr) { + fl_keyboard_manager_notify_layout_changed(handler_); + } + } + + private: + FlMockViewDelegate* view_; + FlKeyboardManager* handler_ = nullptr; + GPtrArray* redispatched_events_ = nullptr; + bool during_redispatch_ = false; + + static gboolean _flushChannelMessagesCb(gpointer data) { + g_autoptr(GMainLoop) loop = reinterpret_cast<GMainLoop*>(data); + g_main_loop_quit(loop); + return FALSE; + } +}; + +// Make sure that the keyboard can be disposed without crashes when there are +// unresolved pending events. +TEST(FlKeyboardManagerTest, DisposeWithUnresolvedPends) { + KeyboardTester tester; + std::vector<CallRecord> call_records; + + // Record calls so that they aren't responded. + tester.recordEmbedderCallsTo(call_records); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + fl_keyboard_manager_handle_event(tester.handler(), event1); + + tester.respondToEmbedderCallsWith(true); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + fl_keyboard_manager_handle_event(tester.handler(), event2); + + tester.flushChannelMessages(); + + // Passes if the cleanup does not crash. +} + +TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { + KeyboardTester tester; + std::vector<CallRecord> call_records; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); + + gboolean handler_handled = false; + + /// Test 1: One event that is handled by the framework + tester.recordEmbedderCallsTo(call_records); + tester.recordRedispatchedEventsTo(redispatched); + + // Dispatch a key event + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event1); + tester.flushChannelMessages(); + EXPECT_EQ(handler_handled, true); + EXPECT_EQ(redispatched->len, 0u); + EXPECT_EQ(call_records.size(), 1u); + EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, + kLogicalKeyA, "a", false); + + call_records[0].callback(true); + tester.flushChannelMessages(); + EXPECT_EQ(redispatched->len, 0u); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); + call_records.clear(); + + /// Test 2: Two events that are unhandled by the framework + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event2); + tester.flushChannelMessages(); + EXPECT_EQ(handler_handled, true); + EXPECT_EQ(redispatched->len, 0u); + EXPECT_EQ(call_records.size(), 1u); + EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, + kLogicalKeyA, nullptr, false); + + // Dispatch another key event + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyB, GDK_KEY_b, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event3); + tester.flushChannelMessages(); + EXPECT_EQ(handler_handled, true); + EXPECT_EQ(redispatched->len, 0u); + EXPECT_EQ(call_records.size(), 2u); + EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeDown, kPhysicalKeyB, + kLogicalKeyB, "b", false); + + // Resolve the second event first to test out-of-order response + call_records[1].callback(false); + EXPECT_EQ(redispatched->len, 1u); + EXPECT_EQ( + fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 0))), + 0x62u); + call_records[0].callback(false); + tester.flushChannelMessages(); + EXPECT_EQ(redispatched->len, 2u); + EXPECT_EQ( + fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 1))), + 0x61u); + + EXPECT_FALSE(fl_keyboard_manager_is_state_clear(tester.handler())); + call_records.clear(); + + // Resolve redispatches + EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 2); + tester.flushChannelMessages(); + EXPECT_EQ(call_records.size(), 0u); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); + + /// Test 3: Dispatch the same event again to ensure that prevention from + /// redispatching only works once. + g_autoptr(FlKeyEvent) event4 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event4); + tester.flushChannelMessages(); + EXPECT_EQ(handler_handled, true); + EXPECT_EQ(redispatched->len, 0u); + EXPECT_EQ(call_records.size(), 1u); + + call_records[0].callback(true); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); +} + +TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { + KeyboardTester tester; + gboolean handler_handled = false; + std::vector<CallRecord> call_records; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); + + /// Test 1: One event that is handled by the framework + tester.respondToEmbedderCallsWithAndRecordsTo(true, call_records); + tester.recordRedispatchedEventsTo(redispatched); + + // Dispatch a key event + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event1); + tester.flushChannelMessages(); + EXPECT_EQ(handler_handled, true); + EXPECT_EQ(call_records.size(), 1u); + EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, + kLogicalKeyA, "a", false); + EXPECT_EQ(redispatched->len, 0u); + call_records.clear(); + + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); + g_ptr_array_set_size(redispatched, 0); + + /// Test 2: An event unhandled by the framework + tester.respondToEmbedderCallsWithAndRecordsTo(false, call_records); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event2); + tester.flushChannelMessages(); + EXPECT_EQ(handler_handled, true); + EXPECT_EQ(call_records.size(), 1u); + EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, + kLogicalKeyA, nullptr, false); + EXPECT_EQ(redispatched->len, 1u); + call_records.clear(); + + EXPECT_FALSE(fl_keyboard_manager_is_state_clear(tester.handler())); + + EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1); + EXPECT_EQ(call_records.size(), 0u); + + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); +} + +TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { + KeyboardTester tester; + std::vector<CallRecord> call_records; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); + + gboolean handler_handled = false; + + tester.recordEmbedderCallsTo(call_records); + tester.recordChannelCallsTo(call_records); + tester.recordRedispatchedEventsTo(redispatched); + + /// Test 1: One delegate responds true, the other false + + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event1); + + EXPECT_EQ(handler_handled, true); + EXPECT_EQ(redispatched->len, 0u); + EXPECT_EQ(call_records.size(), 2u); + + EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); + EXPECT_EQ(call_records[1].type, CallRecord::kKeyCallChannel); + + call_records[0].callback(true); + call_records[1].callback(false); + tester.flushChannelMessages(); + EXPECT_EQ(redispatched->len, 0u); + + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); + call_records.clear(); + + /// Test 2: All delegates respond false + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event2); + + EXPECT_EQ(handler_handled, true); + EXPECT_EQ(redispatched->len, 0u); + EXPECT_EQ(call_records.size(), 2u); + + EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); + EXPECT_EQ(call_records[1].type, CallRecord::kKeyCallChannel); + + call_records[0].callback(false); + call_records[1].callback(false); + + call_records.clear(); + + // Resolve redispatch + tester.flushChannelMessages(); + EXPECT_EQ(redispatched->len, 1u); + EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1); + EXPECT_EQ(call_records.size(), 0u); + + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); +} + +TEST(FlKeyboardManagerTest, TextInputHandlerReturnsFalse) { + KeyboardTester tester; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); + gboolean handler_handled = false; + tester.recordRedispatchedEventsTo(redispatched); + tester.respondToTextInputWith(false); + + // Dispatch a key event. + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event); + tester.flushChannelMessages(); + EXPECT_EQ(handler_handled, true); + // The event was redispatched because no one handles it. + EXPECT_EQ(redispatched->len, 1u); + + // Resolve redispatched event. + EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1); + + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); +} + +TEST(FlKeyboardManagerTest, TextInputHandlerReturnsTrue) { + KeyboardTester tester; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); + gboolean handler_handled = false; + tester.recordRedispatchedEventsTo(redispatched); + tester.respondToTextInputWith(true); + + // Dispatch a key event. + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + handler_handled = fl_keyboard_manager_handle_event(tester.handler(), event); + tester.flushChannelMessages(); + EXPECT_EQ(handler_handled, true); + // The event was not redispatched because handler handles it. + EXPECT_EQ(redispatched->len, 0u); + + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(tester.handler())); +} + +TEST(FlKeyboardManagerTest, CorrectLogicalKeyForLayouts) { + KeyboardTester tester; + + std::vector<CallRecord> call_records; + tester.recordEmbedderCallsTo(call_records); + + auto sendTap = [&](guint8 keycode, guint keyval, guint8 group) { + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, keycode, keyval, static_cast<GdkModifierType>(0), group); + fl_keyboard_manager_handle_event(tester.handler(), event1); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, keycode, keyval, static_cast<GdkModifierType>(0), group); + fl_keyboard_manager_handle_event(tester.handler(), event2); + }; + + /* US keyboard layout */ + + sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA + VERIFY_DOWN(kLogicalKeyA, "a"); + + sendTap(kKeyCodeKeyA, GDK_KEY_A, 0); // Shift-KeyA + VERIFY_DOWN(kLogicalKeyA, "A"); + + sendTap(kKeyCodeDigit1, GDK_KEY_1, 0); // Digit1 + VERIFY_DOWN(kLogicalDigit1, "1"); + + sendTap(kKeyCodeDigit1, GDK_KEY_exclam, 0); // Shift-Digit1 + VERIFY_DOWN(kLogicalDigit1, "!"); + + sendTap(kKeyCodeMinus, GDK_KEY_minus, 0); // Minus + VERIFY_DOWN(kLogicalMinus, "-"); + + sendTap(kKeyCodeMinus, GDK_KEY_underscore, 0); // Shift-Minus + VERIFY_DOWN(kLogicalUnderscore, "_"); + + /* French keyboard layout, group 3, which is when the input method is showing + * "Fr" */ + + tester.setLayout(kLayoutFrench); + + sendTap(kKeyCodeKeyA, GDK_KEY_q, 3); // KeyA + VERIFY_DOWN(kLogicalKeyQ, "q"); + + sendTap(kKeyCodeKeyA, GDK_KEY_Q, 3); // Shift-KeyA + VERIFY_DOWN(kLogicalKeyQ, "Q"); + + sendTap(kKeyCodeSemicolon, GDK_KEY_m, 3); // ; but prints M + VERIFY_DOWN(kLogicalKeyM, "m"); + + sendTap(kKeyCodeKeyM, GDK_KEY_comma, 3); // M but prints , + VERIFY_DOWN(kLogicalComma, ","); + + sendTap(kKeyCodeDigit1, GDK_KEY_ampersand, 3); // Digit1 + VERIFY_DOWN(kLogicalDigit1, "&"); + + sendTap(kKeyCodeDigit1, GDK_KEY_1, 3); // Shift-Digit1 + VERIFY_DOWN(kLogicalDigit1, "1"); + + sendTap(kKeyCodeMinus, GDK_KEY_parenright, 3); // Minus + VERIFY_DOWN(kLogicalParenthesisRight, ")"); + + sendTap(kKeyCodeMinus, GDK_KEY_degree, 3); // Shift-Minus + VERIFY_DOWN(static_cast<uint32_t>(L'°'), "°"); + + /* French keyboard layout, group 0, which is pressing the "extra key for + * triggering input method" key once after switching to French IME. */ + + sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA + VERIFY_DOWN(kLogicalKeyA, "a"); + + sendTap(kKeyCodeDigit1, GDK_KEY_1, 0); // Digit1 + VERIFY_DOWN(kLogicalDigit1, "1"); + + /* Russian keyboard layout, group 2 */ + tester.setLayout(kLayoutRussian); + + sendTap(kKeyCodeKeyA, GDK_KEY_Cyrillic_ef, 2); // KeyA + VERIFY_DOWN(kLogicalKeyA, "ф"); + + sendTap(kKeyCodeDigit1, GDK_KEY_1, 2); // Shift-Digit1 + VERIFY_DOWN(kLogicalDigit1, "1"); + + sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_Cyrillic_ha, 2); + VERIFY_DOWN(kLogicalBracketLeft, "х"); + + /* Russian keyboard layout, group 0 */ + sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA + VERIFY_DOWN(kLogicalKeyA, "a"); + + sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_bracketleft, 0); + VERIFY_DOWN(kLogicalBracketLeft, "["); +} + +TEST(FlKeyboardManagerTest, SynthesizeModifiersIfNeeded) { + KeyboardTester tester; + std::vector<CallRecord> call_records; + tester.recordEmbedderCallsTo(call_records); + + auto verifyModifierIsSynthesized = [&](GdkModifierType mask, + uint64_t physical, uint64_t logical) { + // Modifier is pressed. + guint state = mask; + fl_keyboard_manager_sync_modifier_if_needed(tester.handler(), state, 1000); + EXPECT_EQ(call_records.size(), 1u); + EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, physical, + logical, NULL, true); + // Modifier is released. + state = state ^ mask; + fl_keyboard_manager_sync_modifier_if_needed(tester.handler(), state, 1001); + EXPECT_EQ(call_records.size(), 2u); + EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeUp, physical, logical, + NULL, true); + call_records.clear(); + }; + + // No modifiers pressed. + guint state = 0; + fl_keyboard_manager_sync_modifier_if_needed(tester.handler(), state, 1000); + EXPECT_EQ(call_records.size(), 0u); + call_records.clear(); + + // Press and release each modifier once. + verifyModifierIsSynthesized(GDK_CONTROL_MASK, kPhysicalControlLeft, + kLogicalControlLeft); + verifyModifierIsSynthesized(GDK_META_MASK, kPhysicalMetaLeft, + kLogicalMetaLeft); + verifyModifierIsSynthesized(GDK_MOD1_MASK, kPhysicalAltLeft, kLogicalAltLeft); + verifyModifierIsSynthesized(GDK_SHIFT_MASK, kPhysicalShiftLeft, + kLogicalShiftLeft); +} + +TEST(FlKeyboardManagerTest, GetPressedState) { + KeyboardTester tester; + tester.respondToTextInputWith(true); + + // Dispatch a key event. + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0); + fl_keyboard_manager_handle_event(tester.handler(), event); + + GHashTable* pressedState = + fl_keyboard_manager_get_pressed_state(tester.handler()); + EXPECT_EQ(g_hash_table_size(pressedState), 1u); + + gpointer physical_key = + g_hash_table_lookup(pressedState, uint64_to_gpointer(kPhysicalKeyA)); + EXPECT_EQ(gpointer_to_uint64(physical_key), kLogicalKeyA); +} + +// The following layout data is generated using DEBUG_PRINT_LAYOUT. + +const MockGroupLayoutData kLayoutUs0{{ + // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 + 0xffff, 0x0031, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08 + 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c + 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10 + 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14 + 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18 + 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c + 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20 + 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24 + 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28 + 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c + 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30 + 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34 + 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38 + 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c + 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 + 0xffff, 0xffff, 0x003c, 0x003e, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x64 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78 + 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c +}}; + +const MockGroupLayoutData kLayoutRussian0{ + // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 + 0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08 + 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c + 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10 + 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14 + 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18 + 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c + 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20 + 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24 + 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28 + 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c + 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30 + 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34 + 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38 + 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c + 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 + 0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c + 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 + 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78 + 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c +}; + +const MockGroupLayoutData kLayoutRussian2{{ + // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 + 0xffff, 0x0031, 0x0021, 0x0000, 0x0031, 0x0021, 0x0032, 0x0022, // 0x08 + 0x0033, 0x06b0, 0x0034, 0x003b, 0x0035, 0x0025, 0x0036, 0x003a, // 0x0c + 0x0037, 0x003f, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10 + 0x002d, 0x005f, 0x003d, 0x002b, 0x0071, 0x0051, 0x0000, 0x0000, // 0x14 + 0x06ca, 0x06ea, 0x06c3, 0x06e3, 0x06d5, 0x06f5, 0x06cb, 0x06eb, // 0x18 + 0x06c5, 0x06e5, 0x06ce, 0x06ee, 0x06c7, 0x06e7, 0x06db, 0x06fb, // 0x1c + 0x06dd, 0x06fd, 0x06da, 0x06fa, 0x06c8, 0x06e8, 0x06df, 0x06ff, // 0x20 + 0x0061, 0x0041, 0x0041, 0x0000, 0x06c6, 0x06e6, 0x06d9, 0x06f9, // 0x24 + 0x06d7, 0x06f7, 0x06c1, 0x06e1, 0x06d0, 0x06f0, 0x06d2, 0x06f2, // 0x28 + 0x06cf, 0x06ef, 0x06cc, 0x06ec, 0x06c4, 0x06e4, 0x06d6, 0x06f6, // 0x2c + 0x06dc, 0x06fc, 0x06a3, 0x06b3, 0x007c, 0x0000, 0x005c, 0x002f, // 0x30 + 0x06d1, 0x06f1, 0x06de, 0x06fe, 0x06d3, 0x06f3, 0x06cd, 0x06ed, // 0x34 + 0x06c9, 0x06e9, 0x06d4, 0x06f4, 0x06d8, 0x06f8, 0x06c2, 0x06e2, // 0x38 + 0x06c0, 0x06e0, 0x002e, 0x002c, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 + 0xffff, 0xffff, 0x003c, 0x003e, 0x002f, 0x007c, 0xffff, 0xffff, // 0x5c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x64 + 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0x0000, // 0x68 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, // 0x78 + 0x00b1, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x7c +}}; + +const MockGroupLayoutData kLayoutFrench0 = { + // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 + 0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08 + 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c + 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10 + 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14 + 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18 + 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c + 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20 + 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24 + 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28 + 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c + 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30 + 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34 + 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38 + 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c + 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 + 0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c + 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 + 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78 + 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c +}; + +const MockGroupLayoutData kLayoutFrench3 = { + // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00 + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04 + 0x0000, 0xffff, 0x0000, 0x0000, 0x0026, 0x0031, 0x00e9, 0x0032, // 0x08 + 0x0022, 0x0033, 0x0027, 0x0034, 0x0028, 0x0035, 0x002d, 0x0036, // 0x0c + 0x00e8, 0x0037, 0x005f, 0x0038, 0x00e7, 0x0039, 0x00e0, 0x0030, // 0x10 + 0x0029, 0x00b0, 0x003d, 0x002b, 0x0000, 0x0000, 0x0061, 0x0041, // 0x14 + 0x0061, 0x0041, 0x007a, 0x005a, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18 + 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c + 0x006f, 0x004f, 0x0070, 0x0050, 0xffff, 0xffff, 0x0024, 0x00a3, // 0x20 + 0x0041, 0x0000, 0x0000, 0x0000, 0x0071, 0x0051, 0x0073, 0x0053, // 0x24 + 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28 + 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x006d, 0x004d, // 0x2c + 0x00f9, 0x0025, 0x00b2, 0x007e, 0x0000, 0x0000, 0x002a, 0x00b5, // 0x30 + 0x0077, 0x0057, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34 + 0x0062, 0x0042, 0x006e, 0x004e, 0x002c, 0x003f, 0x003b, 0x002e, // 0x38 + 0x003a, 0x002f, 0x0021, 0x00a7, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58 + 0xffff, 0x003c, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c + 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68 + 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74 + 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, // 0x78 + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x7c +}; + +const MockLayoutData kLayoutUs{&kLayoutUs0}; +const MockLayoutData kLayoutRussian{&kLayoutRussian0, nullptr, + &kLayoutRussian2}; +const MockLayoutData kLayoutFrench{&kLayoutFrench0, nullptr, nullptr, + &kLayoutFrench3}; + +} // namespace
diff --git a/shell/platform/linux/fl_keyboard_view_delegate.cc b/shell/platform/linux/fl_keyboard_view_delegate.cc index e1301c1..771e428 100644 --- a/shell/platform/linux/fl_keyboard_view_delegate.cc +++ b/shell/platform/linux/fl_keyboard_view_delegate.cc
@@ -32,13 +32,6 @@ self, event); } -FlBinaryMessenger* fl_keyboard_view_delegate_get_messenger( - FlKeyboardViewDelegate* self) { - g_return_val_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(self), nullptr); - - return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->get_messenger(self); -} - void fl_keyboard_view_delegate_redispatch_event(FlKeyboardViewDelegate* self, FlKeyEvent* event) { g_return_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(self));
diff --git a/shell/platform/linux/fl_keyboard_view_delegate.h b/shell/platform/linux/fl_keyboard_view_delegate.h index eb1104f..1342390 100644 --- a/shell/platform/linux/fl_keyboard_view_delegate.h +++ b/shell/platform/linux/fl_keyboard_view_delegate.h
@@ -42,8 +42,6 @@ gboolean (*text_filter_key_press)(FlKeyboardViewDelegate* delegate, FlKeyEvent* event); - FlBinaryMessenger* (*get_messenger)(FlKeyboardViewDelegate* delegate); - void (*redispatch_event)(FlKeyboardViewDelegate* delegate, FlKeyEvent* event); guint (*lookup_key)(FlKeyboardViewDelegate* view_delegate, @@ -82,17 +80,6 @@ FlKeyEvent* event); /** - * fl_keyboard_view_delegate_get_messenger: - * - * Returns a binary messenger that can be used to send messages to the - * framework. - * - * The ownership of messenger is kept by the view delegate. - */ -FlBinaryMessenger* fl_keyboard_view_delegate_get_messenger( - FlKeyboardViewDelegate* delegate); - -/** * fl_keyboard_view_delegate_redispatch_event: * * Handles `FlKeyboardHandler`'s request to insert a GDK event to the system for
diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 6e44ecb..3828f8e 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc
@@ -17,6 +17,7 @@ #include "flutter/shell/platform/linux/fl_framebuffer.h" #include "flutter/shell/platform/linux/fl_key_event.h" #include "flutter/shell/platform/linux/fl_keyboard_handler.h" +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/fl_keyboard_view_delegate.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h" #include "flutter/shell/platform/linux/fl_platform_handler.h" @@ -63,6 +64,8 @@ FlScrollingManager* scrolling_manager; + FlKeyboardManager* keyboard_manager; + // Flutter system channel handlers. FlKeyboardHandler* keyboard_handler; FlTextInputHandler* text_input_handler; @@ -151,6 +154,9 @@ g_clear_object(&self->keyboard_handler); self->keyboard_handler = fl_keyboard_handler_new(messenger, FL_KEYBOARD_VIEW_DELEGATE(self)); + g_clear_object(&self->keyboard_manager); + self->keyboard_manager = + fl_keyboard_manager_new(messenger, FL_KEYBOARD_VIEW_DELEGATE(self)); } static void init_scrolling(FlView* self) { @@ -230,7 +236,7 @@ gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self)); fl_scrolling_manager_set_last_mouse_position( self->scrolling_manager, event_x * scale_factor, event_y * scale_factor); - fl_keyboard_handler_sync_modifier_if_needed(self->keyboard_handler, + fl_keyboard_manager_sync_modifier_if_needed(self->keyboard_manager, event_state, event_time); fl_engine_send_mouse_pointer_event( self->engine, self->view_id, phase, @@ -379,11 +385,6 @@ event); }; - iface->get_messenger = [](FlKeyboardViewDelegate* view_delegate) { - FlView* self = FL_VIEW(view_delegate); - return fl_engine_get_binary_messenger(self->engine); - }; - iface->redispatch_event = [](FlKeyboardViewDelegate* view_delegate, FlKeyEvent* event) { GdkEventType event_type = @@ -500,7 +501,7 @@ gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self)); - fl_keyboard_handler_sync_modifier_if_needed(self->keyboard_handler, + fl_keyboard_manager_sync_modifier_if_needed(self->keyboard_manager, event_state, event_time); fl_engine_send_mouse_pointer_event( self->engine, self->view_id, self->button_state != 0 ? kMove : kHover, @@ -559,7 +560,7 @@ } static void keymap_keys_changed_cb(FlView* self) { - fl_keyboard_handler_notify_layout_changed(self->keyboard_handler); + fl_keyboard_manager_notify_layout_changed(self->keyboard_manager); } static void gesture_rotation_begin_cb(FlView* self) { @@ -728,11 +729,12 @@ g_clear_pointer(&self->background_color, gdk_rgba_free); g_clear_object(&self->window_state_monitor); g_clear_object(&self->scrolling_manager); - g_clear_object(&self->keyboard_handler); + g_clear_object(&self->keyboard_manager); if (self->keymap_keys_changed_cb_id != 0) { g_signal_handler_disconnect(self->keymap, self->keymap_keys_changed_cb_id); self->keymap_keys_changed_cb_id = 0; } + g_clear_object(&self->keyboard_handler); g_clear_object(&self->mouse_cursor_handler); g_clear_object(&self->platform_handler); g_clear_object(&self->view_accessible); @@ -755,8 +757,8 @@ static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - return fl_keyboard_handler_handle_event( - self->keyboard_handler, fl_key_event_new_from_gdk_event(gdk_event_copy( + return fl_keyboard_manager_handle_event( + self->keyboard_manager, fl_key_event_new_from_gdk_event(gdk_event_copy( reinterpret_cast<GdkEvent*>(event)))); } @@ -764,8 +766,8 @@ static gboolean fl_view_key_release_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - return fl_keyboard_handler_handle_event( - self->keyboard_handler, fl_key_event_new_from_gdk_event(gdk_event_copy( + return fl_keyboard_manager_handle_event( + self->keyboard_manager, fl_key_event_new_from_gdk_event(gdk_event_copy( reinterpret_cast<GdkEvent*>(event)))); } @@ -911,5 +913,5 @@ GHashTable* fl_view_get_keyboard_state(FlView* self) { g_return_val_if_fail(FL_IS_VIEW(self), nullptr); - return fl_keyboard_handler_get_pressed_state(self->keyboard_handler); + return fl_keyboard_manager_get_pressed_state(self->keyboard_manager); }
diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index 1d758e4..82c2017 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE
@@ -32054,7 +32054,7 @@ This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/d916a5f69a486de98316900f19ef0ff46834b03d +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/993d3069f42e98b2b29e441bc98424065cc255ca /third_party/fallback_root_certificates/ --------------------------------------------------------------------------------
diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index 8952a74..ef3b466 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt
@@ -545,6 +545,9 @@ impeller_Play_AiksTest_CoverageOriginShouldBeAccountedForInSubpasses_Metal.png impeller_Play_AiksTest_CoverageOriginShouldBeAccountedForInSubpasses_OpenGLES.png impeller_Play_AiksTest_CoverageOriginShouldBeAccountedForInSubpasses_Vulkan.png +impeller_Play_AiksTest_DestructiveBlendColorFilterFloodsClip_Metal.png +impeller_Play_AiksTest_DestructiveBlendColorFilterFloodsClip_OpenGLES.png +impeller_Play_AiksTest_DestructiveBlendColorFilterFloodsClip_Vulkan.png impeller_Play_AiksTest_DispatcherDoesNotCullPerspectiveTransformedChildDisplayLists_Metal.png impeller_Play_AiksTest_DispatcherDoesNotCullPerspectiveTransformedChildDisplayLists_OpenGLES.png impeller_Play_AiksTest_DispatcherDoesNotCullPerspectiveTransformedChildDisplayLists_Vulkan.png
diff --git a/tools/yapf.sh b/tools/yapf.sh index 48d0974..bab0071 100755 --- a/tools/yapf.sh +++ b/tools/yapf.sh
@@ -36,5 +36,19 @@ SCRIPT_DIR=$(follow_links "$(dirname -- "${BASH_SOURCE[0]}")") SRC_DIR="$(cd "$SCRIPT_DIR/../.."; pwd -P)" YAPF_DIR="$(cd "$SRC_DIR/flutter/third_party/yapf"; pwd -P)" +if command -v python3.10 &> /dev/null; then + PYTHON_EXEC="python3.10" +else + python3 -c " +import sys +version = sys.version_info +if (version.major, version.minor) > (3, 10): + print(f'Error: python3 version {version.major}.{version.minor} is greater than 3.10.', file=sys.stderr) + sys.exit(1) +else: + print(f'Using python3 version {version.major}.{version.minor}.') +" || exit 1 + PYTHON_EXEC="python3" +fi -PYTHONPATH="$YAPF_DIR" python3 "$YAPF_DIR/yapf" "$@" +PYTHONPATH="$YAPF_DIR" $PYTHON_EXEC "$YAPF_DIR/yapf" "$@"