diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c1c1d3d05f37b..ce1c48a3dcf3f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,13 +18,13 @@ If you need help, consider asking for advice on the #hackers-new channel on [Discord]. -[Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview -[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene -[test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests -[Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo +[Contributor Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview +[Tree Hygiene]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md +[test-exempt]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests +[Flutter Style Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style -[testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine +[testing the engine]: https://github.com/flutter/engine/blob/main/docs/testing/Testing-the-engine.md [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests -[breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes -[Discord]: https://github.com/flutter/flutter/wiki/Chat +[breaking change policy]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#handling-breaking-changes +[Discord]: https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md diff --git a/DEPS b/DEPS index 46e31d0631c72..d7bde6d4372c3 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'ded8ab47ee69051fd29711ae86d33e8fee119ebb', + 'skia_revision': 'bd7d952398d511dbba69346c912eccd445126d5d', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. @@ -56,27 +56,26 @@ vars = { # 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': 'df716eaa6ed2c4778cea0bcb449e023c7ccd3a73', + 'dart_revision': '1a28e6c86b09f1c83365f54388c32ed97c9e9b31', # 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': '93883fde36ac158fd415dcd6dbd387dcfd928d3c', - 'dart_boringssl_gen_rev': 'fef055e8d2749b82c79c8f043be1cbe5e8e4b40c', - 'dart_boringssl_rev': '2db0eb3f96a5756298dcd7f9319e56a98585bd10', - 'dart_core_rev': '1de837279d3c4ce21fef2a5af8a7f0b668ef3d85', - 'dart_devtools_rev': '3642846c465888b0c56271fe9265a0901f1803f6', + 'dart_boringssl_rev': 'bb13a96931dd90d6570fa6151e19ef426d5c641f', + 'dart_core_rev': '7f9f597e64fa52faebd3c0a2214f61a7b081174d', + 'dart_devtools_rev': '3e5327a02693b1405359dc5322d7f0a40151b9b7', 'dart_http_rev': '79470d014b467f01b0e7c5b63ab6c86b22dec8db', 'dart_libprotobuf_rev': '24487dd1045c7f3d64a21f38a3f0c06cc4cf2edb', 'dart_perfetto_rev': '13ce0c9e13b0940d2476cd0cff2301708a9a2e2b', 'dart_protobuf_gn_rev': 'ca669f79945418f6229e4fef89b666b2a88cbb10', - 'dart_protobuf_rev': 'ccf104dbc36929c0f8708285d5f3a8fae206343e', - 'dart_pub_rev': '8c2e621c2403cb503cc9959be387d1061a16846a', - 'dart_tools_rev': 'a6603a45374fc2ed9de4cf0297bde003f141dc9b', - 'dart_watcher_rev': '7a15a903f7ce0737cce7d08ff30402d41b9f7b62', - 'dart_web_rev': '8d243766b45c163a9d18a89de059eba24398d163', + 'dart_protobuf_rev': 'da7279c56734cffed4deb1e3a6f93bdcefccf6b8', + 'dart_pub_rev': '30bfc439fedba1ee3daadcf542f1483479bc4909', + 'dart_tools_rev': '223daf5300a5e3f6e09b7e24a5fda1009d6708f7', + 'dart_watcher_rev': 'bc44e6f6b85972e516c44b9ae6c042b4cbd7c72b', + 'dart_web_rev': 'bdf112ec64d28285cc29c6c78274ff3a827bb79b', 'dart_webdev_rev': '5f30c560dc4e3df341356c43ec1a766ee6b74a7c', - 'dart_webkit_inspection_protocol_rev': 'a834c3b700ead5f1157740d6585ab374f8af1507', - 'dart_yaml_edit_rev': '8bd0fdfbe1e5119367500543d68be10691efce58', + 'dart_webkit_inspection_protocol_rev': 'effa75205516757795683d527c3dea9546eb0c32', + 'dart_yaml_edit_rev': 'fbdc70acc164af187772e013a2e1364cd05b88dc', 'ocmock_rev': 'c4ec0e3a7a9f56cfdbd0aa01f4f97bb4b75c5ef8', # v3.7.1 @@ -151,7 +150,6 @@ vars = { "upstream_angle": "https://github.com/google/angle.git", "upstream_archive": "https://github.com/brendan-duncan/archive.git", "upstream_benchmark": "https://github.com/google/benchmark.git", - "upstream_boringssl_gen": "https://github.com/dart-lang/boringssl_gen.git", "upstream_boringssl": "https://github.com/openssl/openssl.git", "upstream_brotli": "https://github.com/google/brotli.git", "upstream_buildroot": "https://github.com/flutter/buildroot.git", @@ -229,7 +227,7 @@ vars = { # The version / instance id of the cipd:chromium/fuchsia/test-scripts which # will be used altogether with fuchsia-sdk to setup the build / test # environment. - 'fuchsia_test_scripts_version': 'OA7UxNZkbxCRfr80Axs8YyBcKZHGw5iUxDDbxiXXTAEC', + 'fuchsia_test_scripts_version': 'r9Dc5VRF6sE3pJH20k2d1Yko3xSlwljH_nuw7O8vcb4C', # The version / instance id of the cipd:chromium/fuchsia/gn-sdk which will be # used altogether with fuchsia-sdk to generate gn based build rules. @@ -296,9 +294,6 @@ deps = { 'src/flutter/third_party/googletest': Var('chromium_git') + '/external/github.com/google/googletest' + '@' + '7f036c5563af7d0329f20e8bb42effb04629f0c0', - 'src/flutter/third_party/boringssl': - Var('dart_git') + '/boringssl_gen.git' + '@' + Var('dart_boringssl_gen_rev'), - 'src/flutter/third_party/brotli': Var('skia_git') + '/external/github.com/google/brotli.git' + '@' + '350100a5bb9d9671aca85213b2ec7a70a361b0cd', @@ -328,25 +323,25 @@ deps = { 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:3642846c465888b0c56271fe9265a0901f1803f6'}]}, + {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:3e5327a02693b1405359dc5322d7f0a40151b9b7'}]}, 'src/flutter/third_party/dart/third_party/pkg/core': Var('dart_git') + '/core.git' + '@' + Var('dart_core_rev'), 'src/flutter/third_party/dart/third_party/pkg/dart_style': - Var('dart_git') + '/dart_style.git@f6d020e48cc531a0967c91fa88028c086fedfbf9', + Var('dart_git') + '/dart_style.git@1de89eb3bd340315f9ff5f2afc319cc1d6131b8d', 'src/flutter/third_party/dart/third_party/pkg/dartdoc': Var('dart_git') + '/dartdoc.git@c7f11603effa88ddacabfd555993f322fca8b3fe', 'src/flutter/third_party/dart/third_party/pkg/glob': - Var('dart_git') + '/glob.git@b6319d6c2880b44039e75dfed80f7ce150f76d51', + Var('dart_git') + '/glob.git@994191a107b99a1911a3ef52ca238cd9305c8d37', 'src/flutter/third_party/dart/third_party/pkg/http': Var('dart_git') + '/http.git' + '@' + Var('dart_http_rev'), 'src/flutter/third_party/dart/third_party/pkg/http_multi_server': - Var('dart_git') + '/http_multi_server.git@c8aabe36268aa38c906eae46728c10d883b9aced', + Var('dart_git') + '/http_multi_server.git@f6a748819139b8cbf513d5fc36b10676b0cb066f', 'src/flutter/third_party/dart/third_party/pkg/intl': Var('dart_git') + '/intl.git@5d65e3808ce40e6282e40881492607df4e35669f', @@ -355,16 +350,16 @@ deps = { Var('dart_git') + '/leak_tracker.git@f5620600a5ce1c44f65ddaa02001e200b096e14c', 'src/flutter/third_party/dart/third_party/pkg/markdown': - Var('dart_git') + '/markdown.git@776689c8749ebddd4ea0ec899085bd2aae0e25ba', + Var('dart_git') + '/markdown.git@4d5dbc659955973902f2585c54e94d453532db70', 'src/flutter/third_party/dart/third_party/pkg/native': - Var('dart_git') + '/native.git@51647776372aa9e1f839efb811aa959fe445c0cf', + Var('dart_git') + '/native.git@8ea1a9db0af42933eb22334c4506ca464d7237e9', 'src/flutter/third_party/dart/third_party/pkg/package_config': - Var('dart_git') + '/package_config.git@2583a4e2f9382409ba3bcfa4887ef2a2a8a2aee3', + Var('dart_git') + '/package_config.git@76f2f6c245451da1fa24d7bbb00251b909e729a5', 'src/flutter/third_party/dart/third_party/pkg/pool': - Var('dart_git') + '/pool.git@0bac9b20ef61ad8bfdd6b92b565dd12e8e2e2c78', + Var('dart_git') + '/pool.git@f85209d83cb0aa3c5612ed80de32df51ba580abd', 'src/flutter/third_party/dart/third_party/pkg/protobuf': Var('dart_git') + '/protobuf.git' + '@' + Var('dart_protobuf_rev'), @@ -373,40 +368,40 @@ deps = { Var('dart_git') + '/pub.git' + '@' + Var('dart_pub_rev'), 'src/flutter/third_party/dart/third_party/pkg/pub_semver': - Var('dart_git') + '/pub_semver.git@ab3eab50cc9f3df650ba7f5571aa2a1ea715dcc8', + Var('dart_git') + '/pub_semver.git@8e9fcb9d3f89f06022387f906da4d380688f935c', 'src/flutter/third_party/dart/third_party/pkg/shelf': - Var('dart_git') + '/shelf.git@a2708cd8bce88d5e6391b1cb5bbe80b5a072c55a', + Var('dart_git') + '/shelf.git@2b5b683e78f5cc84e479a43297fd7b5489d7db02', 'src/flutter/third_party/dart/third_party/pkg/source_maps': - Var('dart_git') + '/source_maps.git@b20b97003a48d78a1ecba7e46d932ea4b480dd94', + Var('dart_git') + '/source_maps.git@198d32bbde2f5736c04dfbab306a17096fd1648b', 'src/flutter/third_party/dart/third_party/pkg/source_span': - Var('dart_git') + '/source_span.git@f147469ba02108c1ade3680de548b7b447de8c72', + Var('dart_git') + '/source_span.git@22a243eb50d926935a8a1300a49af6d2988c3ae6', 'src/flutter/third_party/dart/third_party/pkg/sse': - Var('dart_git') + '/sse.git@befbd6d35118f59525903242db3888942ac34180', + Var('dart_git') + '/sse.git@b97dc3ad9a58a454dc5ffe5b3ec814dadc389e32', 'src/flutter/third_party/dart/third_party/pkg/stack_trace': - Var('dart_git') + '/stack_trace.git@63e79f584567f7c73e7f5739c7cfd8e748f51f16', + Var('dart_git') + '/stack_trace.git@b660cfa444d46bcceb3a0eacbd6a2a7829da11de', 'src/flutter/third_party/dart/third_party/pkg/stream_channel': - Var('dart_git') + '/stream_channel.git@9bfc2a8dec202bcd07332f39df0f905c670092c6', + Var('dart_git') + '/stream_channel.git@71fe6dd315e7f451466da80f7af2661cd28aaaea', 'src/flutter/third_party/dart/third_party/pkg/string_scanner': - Var('dart_git') + '/string_scanner.git@255d67111e3ed67caedba2789269b6344bf62638', + Var('dart_git') + '/string_scanner.git@77de235c061a09264cae920e52939787325c8cae', 'src/flutter/third_party/dart/third_party/pkg/tar': 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@31abb04b735395ba98db3dd4a360b85729dfddfa', + Var('dart_git') + '/term_glyph.git@9ed8ed96fdd84cb7b72ee1be3e86010969fa95d4', 'src/flutter/third_party/dart/third_party/pkg/test': - Var('dart_git') + '/test.git@8a07bee398833ca38ca4c88905ccdbd513f40705', + Var('dart_git') + '/test.git@dc0f8ea4d09aabb0fed16daea3d4653c8f967b02', 'src/flutter/third_party/dart/third_party/pkg/test_reflective_loader': - Var('dart_git') + '/test_reflective_loader.git@30a552df6421e1f68cdc33c98c2512984b6f42b9', + Var('dart_git') + '/test_reflective_loader.git@faade6299d1823f0d062eb5e98f3b440ddcea7c6', 'src/flutter/third_party/dart/third_party/pkg/tools': Var('dart_git') + '/tools.git' + '@' + Var('dart_tools_rev'), @@ -418,7 +413,7 @@ deps = { 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@abe77eabb6566a2d5129d1178ef2e342ca578e64', + Var('dart_git') + '/web_socket_channel.git@7a2039fd7c4c656ab27850926f89103b5f188dab', 'src/flutter/third_party/dart/third_party/pkg/webdev': Var('dart_git') + '/webdev.git' + '@' + Var('dart_webdev_rev'), @@ -427,7 +422,7 @@ deps = { Var('dart_git') + '/external/github.com/google/webkit_inspection_protocol.dart.git' + '@' + Var('dart_webkit_inspection_protocol_rev'), 'src/flutter/third_party/dart/third_party/pkg/yaml': - Var('dart_git') + '/yaml.git@402655e84389bd1a4208000d75c16d1e5faeb443', + Var('dart_git') + '/yaml.git@2a3727288a9336b6f9b7c5236657414ce1ee5d8a', 'src/flutter/third_party/dart/third_party/pkg/yaml_edit': Var('dart_git') + '/yaml_edit.git' + '@' + Var('dart_yaml_edit_rev'), @@ -875,7 +870,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'D5CBHuB2c-v3Zai-ctZfl5OU4d13Q1Af5LYFMrzdpVIC' + 'version': '5taAI9-tnFN84ZJvrs2E-sXIhxas7Bw7jxCrLtzcnaEC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/analysis_options.yaml b/analysis_options.yaml index 3991dcfa1b2da..f06dc36175322 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -23,6 +23,9 @@ analyzer: - third_party - shell/platform/fuchsia +formatter: + page_width: 100 + linter: rules: # This list is derived from the list of all available lints located at diff --git a/ci/bin/format.dart b/ci/bin/format.dart index b165dd5a7854c..88390bd826256 100644 --- a/ci/bin/format.dart +++ b/ci/bin/format.dart @@ -6,6 +6,7 @@ // // Run with --help for usage. +import 'dart:ffi'; import 'dart:io'; import 'package:args/args.dart'; @@ -312,17 +313,15 @@ class ClangFormatChecker extends FormatChecker { super.allFiles, super.messageCallback, }) { - /*late*/ String clangOs; - if (Platform.isLinux) { - clangOs = 'linux-x64'; - } else if (Platform.isMacOS) { - clangOs = 'mac-x64'; - } else if (Platform.isWindows) { - clangOs = 'windows-x64'; - } else { - throw FormattingException( - "Unknown operating system: don't know how to run clang-format here."); - } + final clangOs = switch (Abi.current()) { + Abi.linuxArm64 => 'linux-arm64', + Abi.linuxX64 => 'linux-x64', + Abi.macosArm64 => 'mac-arm64', + Abi.macosX64 => 'mac-x64', + Abi.windowsX64 => 'windows-x64', + (_) => throw FormattingException( + "Unknown operating system: don't know how to run clang-format here.") + }; clangFormat = File( path.join( srcDir.absolute.path, diff --git a/ci/format.sh b/ci/format.sh index 8bdd9424d010f..c402102d6c8a8 100755 --- a/ci/format.sh +++ b/ci/format.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2013 The Flutter Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 1883a2b7c4b00..fc87ccf46c344 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -182,7 +182,10 @@ ../../../flutter/impeller/geometry/trig_unittests.cc ../../../flutter/impeller/golden_tests/README.md ../../../flutter/impeller/playground +../../../flutter/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc +../../../flutter/impeller/renderer/backend/gles/device_buffer_gles_unittests.cc ../../../flutter/impeller/renderer/backend/gles/test +../../../flutter/impeller/renderer/backend/gles/unique_handle_gles_unittests.cc ../../../flutter/impeller/renderer/backend/metal/allocator_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/metal/texture_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk_unittests.cc @@ -945,12 +948,9 @@ ../../../flutter/third_party/angle/tools ../../../flutter/third_party/angle/util ../../../flutter/third_party/benchmark -../../../flutter/third_party/boringssl/.git -../../../flutter/third_party/boringssl/.gitignore -../../../flutter/third_party/boringssl/OWNERS -../../../flutter/third_party/boringssl/README -../../../flutter/third_party/boringssl/codereview.settings ../../../flutter/third_party/boringssl/src/.bazelrc +../../../flutter/third_party/boringssl/src/.bazelversion +../../../flutter/third_party/boringssl/src/.bcr/README.md ../../../flutter/third_party/boringssl/src/.clang-format ../../../flutter/third_party/boringssl/src/.git ../../../flutter/third_party/boringssl/src/.github @@ -1015,11 +1015,8 @@ ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256_test.cc ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hkdf/hkdf_test.cc -../../../flutter/third_party/boringssl/src/crypto/fipsmodule/md5/md5_test.cc ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm_test.cc ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/ctrdrbg_test.cc -../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/fork_detect_test.cc -../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/urandom_test.cc ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/service_indicator/service_indicator_test.cc ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha_test.cc ../../../flutter/third_party/boringssl/src/crypto/hmac_extra/hmac_test.cc @@ -1030,6 +1027,9 @@ ../../../flutter/third_party/boringssl/src/crypto/keccak/keccak_test.cc ../../../flutter/third_party/boringssl/src/crypto/kyber/kyber_test.cc ../../../flutter/third_party/boringssl/src/crypto/lhash/lhash_test.cc +../../../flutter/third_party/boringssl/src/crypto/md5/md5_test.cc +../../../flutter/third_party/boringssl/src/crypto/mldsa/mldsa_test.cc +../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem_test.cc ../../../flutter/third_party/boringssl/src/crypto/obj/README ../../../flutter/third_party/boringssl/src/crypto/obj/obj_test.cc ../../../flutter/third_party/boringssl/src/crypto/pem/pem_test.cc @@ -1040,13 +1040,15 @@ ../../../flutter/third_party/boringssl/src/crypto/pkcs8/test ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_test.cc ../../../flutter/third_party/boringssl/src/crypto/pool/pool_test.cc +../../../flutter/third_party/boringssl/src/crypto/rand_extra/fork_detect_test.cc ../../../flutter/third_party/boringssl/src/crypto/rand_extra/getentropy_test.cc ../../../flutter/third_party/boringssl/src/crypto/rand_extra/rand_test.cc +../../../flutter/third_party/boringssl/src/crypto/rand_extra/urandom_test.cc ../../../flutter/third_party/boringssl/src/crypto/refcount_test.cc ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_test.cc ../../../flutter/third_party/boringssl/src/crypto/self_test.cc ../../../flutter/third_party/boringssl/src/crypto/siphash/siphash_test.cc -../../../flutter/third_party/boringssl/src/crypto/spx/spx_test.cc +../../../flutter/third_party/boringssl/src/crypto/slhdsa/slhdsa_test.cc ../../../flutter/third_party/boringssl/src/crypto/stack/stack_test.cc ../../../flutter/third_party/boringssl/src/crypto/test ../../../flutter/third_party/boringssl/src/crypto/thread_test.cc @@ -1067,6 +1069,7 @@ ../../../flutter/third_party/boringssl/src/gen/sources.bzl ../../../flutter/third_party/boringssl/src/gen/sources.cmake ../../../flutter/third_party/boringssl/src/gen/test_support +../../../flutter/third_party/boringssl/src/infra/config/README.md ../../../flutter/third_party/boringssl/src/pki/README.md ../../../flutter/third_party/boringssl/src/pki/cert_issuer_source_static_unittest.cc ../../../flutter/third_party/boringssl/src/pki/cert_issuer_source_sync_unittest.h @@ -1102,9 +1105,11 @@ ../../../flutter/third_party/boringssl/src/pki/verify_certificate_chain_unittest.cc ../../../flutter/third_party/boringssl/src/pki/verify_name_match_unittest.cc ../../../flutter/third_party/boringssl/src/pki/verify_signed_data_unittest.cc +../../../flutter/third_party/boringssl/src/pki/verify_unittest.cc ../../../flutter/third_party/boringssl/src/rust ../../../flutter/third_party/boringssl/src/ssl/span_test.cc ../../../flutter/third_party/boringssl/src/ssl/ssl_c_test.c +../../../flutter/third_party/boringssl/src/ssl/ssl_internal_test.cc ../../../flutter/third_party/boringssl/src/ssl/ssl_test.cc ../../../flutter/third_party/boringssl/src/ssl/test ../../../flutter/third_party/boringssl/src/third_party/fiat/METADATA @@ -1239,6 +1244,10 @@ ../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/kw_test.txt ../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/kwp_test.json ../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/kwp_test.txt +../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/mldsa_65_standard_sign_test.json +../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/mldsa_65_standard_sign_test.txt +../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/mldsa_65_standard_verify_test.json +../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/mldsa_65_standard_verify_test.txt ../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/primality_test.json ../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/primality_test.txt ../../../flutter/third_party/boringssl/src/third_party/wycheproof_testvectors/rsa_oaep_2048_sha1_mgf1sha1_test.json @@ -1655,6 +1664,7 @@ ../../../flutter/third_party/dart/third_party/OWNERS ../../../flutter/third_party/dart/third_party/binary_size ../../../flutter/third_party/dart/third_party/binaryen +../../../flutter/third_party/dart/third_party/boringssl/OWNERS ../../../flutter/third_party/dart/third_party/clang.tar.gz.sha1 ../../../flutter/third_party/dart/third_party/cpu_features/OWNERS ../../../flutter/third_party/dart/third_party/cpu_features/README.chromium @@ -2794,6 +2804,7 @@ ../../../flutter/third_party/skia/modules/canvaskit/wasm_tools/SIMD/.gitignore ../../../flutter/third_party/skia/modules/jetski/BUILD.bazel ../../../flutter/third_party/skia/modules/jetski/README +../../../flutter/third_party/skia/modules/jsonreader/BUILD.bazel ../../../flutter/third_party/skia/modules/pathkit/.gitignore ../../../flutter/third_party/skia/modules/pathkit/BUILD.bazel ../../../flutter/third_party/skia/modules/pathkit/CHANGELOG.md @@ -3298,6 +3309,7 @@ ../../../fuchsia/sdk/linux/bind/fuchsia.gpio/meta.json ../../../fuchsia/sdk/linux/bind/fuchsia.i2c/meta.json ../../../fuchsia/sdk/linux/bind/fuchsia.khadas.platform/meta.json +../../../fuchsia/sdk/linux/bind/fuchsia.mailbox/meta.json ../../../fuchsia/sdk/linux/bind/fuchsia.nxp.platform/meta.json ../../../fuchsia/sdk/linux/bind/fuchsia.pci/meta.json ../../../fuchsia/sdk/linux/bind/fuchsia.platform/meta.json @@ -3386,6 +3398,7 @@ ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.i2c/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.i2cimpl/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.light/meta.json +../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.mailbox/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.network.driver/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.network/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pci/meta.json @@ -3399,6 +3412,7 @@ ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.radar/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.registers/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.rtc/meta.json +../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.sdhci/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.sdio/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.sdmmc/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.serial/meta.json diff --git a/ci/licenses_golden/licenses_dart b/ci/licenses_golden/licenses_dart index 3993c71d427d4..23615dc9b005d 100644 --- a/ci/licenses_golden/licenses_dart +++ b/ci/licenses_golden/licenses_dart @@ -1,4 +1,4 @@ -Signature: 8066315dc6f0f7124a5f8676e0277f19 +Signature: 88b861f153b1524223e9c67bfdbe479d ==================================================================================================== LIBRARY: dart @@ -4092,6 +4092,7 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/vm/heap/incremental_compactor. ORIGIN: ../../../flutter/third_party/dart/runtime/vm/interpreter.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/interpreter.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/os.cc + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/vm/simulator_memory.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/stack_frame_kbc.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_dev_runtime/private/custom_hash_set.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_dev_runtime/private/ddc_only.dart + ../../../flutter/third_party/dart/LICENSE @@ -4102,6 +4103,7 @@ ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_runtime/lib/synce ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_runtime/lib/synced/invocation_mirror_constants.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_shared/lib/date_time_patch.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/js_shared/lib/synced/async_status_codes.dart + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/vm/bin/resident_compiler_utils.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/vm/lib/concurrent_patch.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/wasm/lib/compact_hash.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/sdk/lib/_internal/wasm/lib/ffi_patch.dart + ../../../flutter/third_party/dart/LICENSE @@ -4145,6 +4147,7 @@ FILE: ../../../flutter/third_party/dart/runtime/vm/heap/incremental_compactor.h FILE: ../../../flutter/third_party/dart/runtime/vm/interpreter.cc FILE: ../../../flutter/third_party/dart/runtime/vm/interpreter.h FILE: ../../../flutter/third_party/dart/runtime/vm/os.cc +FILE: ../../../flutter/third_party/dart/runtime/vm/simulator_memory.h FILE: ../../../flutter/third_party/dart/runtime/vm/stack_frame_kbc.h FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_dev_runtime/private/custom_hash_set.dart FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_dev_runtime/private/ddc_only.dart @@ -4155,6 +4158,7 @@ FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_runtime/lib/synced/ FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_runtime/lib/synced/invocation_mirror_constants.dart FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_shared/lib/date_time_patch.dart FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/js_shared/lib/synced/async_status_codes.dart +FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/vm/bin/resident_compiler_utils.dart FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/vm/lib/concurrent_patch.dart FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/wasm/lib/compact_hash.dart FILE: ../../../flutter/third_party/dart/sdk/lib/_internal/wasm/lib/ffi_patch.dart @@ -4803,7 +4807,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice 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/+/eb01a0430f728c91af32390b16362528f3fed585 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/1a28e6c86b09f1c83365f54388c32ed97c9e9b31 /third_party/fallback_root_certificates/ ==================================================================================================== diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index a278436eb9283..6e12ed7f3cd7e 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -11563,163 +11563,162 @@ copied and put under another distribution licence ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_bitstr.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_bool.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_d2i_fp.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_dup.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_gentm.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_i2d_fp.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_int.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_mbstr.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_object.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_octet.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_strex.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_strnid.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_time.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_type.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_utctm.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn1_lib.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn1_par.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn_pack.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/f_int.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/f_string.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_dec.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_enc.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_fre.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_new.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_typ.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_utl.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/base64/base64.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/bio.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/bio_mem.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/connect.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/errno.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/fd.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/file.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/hexdump.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_bitstr.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_bool.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_d2i_fp.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_dup.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_gentm.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_i2d_fp.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_int.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_mbstr.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_object.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_octet.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_strex.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_strnid.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_time.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_type.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_utctm.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn1_lib.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn1_par.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn_pack.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/f_int.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/f_string.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_dec.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_enc.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_fre.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_new.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_typ.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_utl.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/base64/base64.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/bio.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/bio_mem.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/connect.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/errno.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/fd.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/file.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/hexdump.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/printf.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/socket.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bn_extra/convert.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/buf/buf.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/cipher_extra.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/derive_key.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_des.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_null.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_rc2.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_rc4.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/printf.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/socket.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bn_extra/convert.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/buf/buf.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/cipher_extra.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/derive_key.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_des.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_null.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_rc2.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_rc4.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/conf/conf.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/conf/conf_def.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_intel.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/des/des.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/conf/conf.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_intel.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/des/des.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/des/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/digest_extra/digest_extra.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dsa/dsa.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/err/err.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/evp.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_asn1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_ctx.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/digest_extra/digest_extra.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dsa/dsa.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/err/err.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/evp.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_asn1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_ctx.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/sign.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ex_data.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/add.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/bn.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/bytes.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/cmp.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/div.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/exponentiation.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/generic.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/mul.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/prime.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/random.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/shift.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/cipher.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/sign.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ex_data.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/add.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/bn.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/bytes.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/cmp.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/div.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/exponentiation.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/generic.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/mul.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/prime.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/random.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/shift.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/cipher.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/check.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/dh.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/digest.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/digests.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/check.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/dh.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/digest.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/digests.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hmac/hmac.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/md4/md4.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/md5/md5.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/blinding.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hmac/hmac.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/blinding.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha256.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha512.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha1.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha256.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha512.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/internal.h ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/lhash/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/lhash/lhash.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/mem.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/obj/obj.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/obj/obj_xref.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_all.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_info.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_lib.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_oth.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_pk8.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_pkey.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rc4/rc4.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/lhash/lhash.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/md4/md4.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/md5/md5.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/mem.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/obj/obj.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/obj/obj_xref.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_all.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_info.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_lib.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_oth.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_pk8.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_pkey.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rc4/rc4.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_crypt.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/stack/stack.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/thread.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/a_digest.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/a_sign.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/a_verify.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/algorithm.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/asn1_gen.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/by_dir.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/by_file.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/i2d_pr.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/name_print.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/t_crl.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/t_req.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/t_x509.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/t_x509a.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_att.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_cmp.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_d2.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_def.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_ext.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_lu.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_obj.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_req.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_set.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_txt.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_v3.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_vfy.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509name.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509rset.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_all.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_attrib.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_crl.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_exten.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_name.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_pubkey.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_req.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_sig.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_spki.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_val.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_x509.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/bio/base64_bio.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/blowfish/blowfish.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/cast/cast.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/cast/cast_tables.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_crypt.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/stack/stack.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/thread.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/a_digest.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/a_sign.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/a_verify.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/algorithm.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/asn1_gen.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/by_dir.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/by_file.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/i2d_pr.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/name_print.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/t_crl.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/t_req.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/t_x509.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/t_x509a.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_att.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_cmp.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_d2.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_def.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_ext.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_lu.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_obj.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_req.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_set.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_txt.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_v3.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_vfy.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509name.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509rset.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_all.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_attrib.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_crl.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_exten.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_name.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_pubkey.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_req.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_sig.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_spki.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_val.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_x509.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/bio/base64_bio.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/blowfish/blowfish.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/cast/cast.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/cast/cast_tables.cc ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/cast/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/des/cfb64ede.c +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/des/cfb64ede.cc ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/macros.h -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/rc4/rc4_decrepit.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/ripemd/ripemd.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/rsa/rsa_decrepit.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/ssl/ssl_decrepit.c +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/rc4/rc4_decrepit.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/ripemd/ripemd.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/rsa/rsa_decrepit.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/ssl/ssl_decrepit.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/asn1.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/base64.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/bio.h @@ -11779,163 +11778,162 @@ ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/t1_enc.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/tls_method.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/tls_record.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_bitstr.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_bool.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_d2i_fp.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_dup.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_gentm.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_i2d_fp.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_int.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_mbstr.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_object.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_octet.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_strex.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_strnid.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_time.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_type.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_utctm.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn1_lib.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn1_par.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn_pack.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/f_int.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/f_string.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_dec.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_enc.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_fre.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_new.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_typ.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_utl.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/base64/base64.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/bio.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/bio_mem.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/connect.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/errno.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/fd.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/file.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/hexdump.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_bitstr.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_bool.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_d2i_fp.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_dup.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_gentm.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_i2d_fp.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_int.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_mbstr.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_object.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_octet.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_strex.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_strnid.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_time.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_type.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/a_utctm.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn1_lib.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn1_par.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/asn_pack.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/f_int.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/f_string.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_dec.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_enc.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_fre.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_new.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_typ.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/tasn_utl.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/base64/base64.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/bio.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/bio_mem.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/connect.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/errno.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/fd.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/file.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/hexdump.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/printf.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/socket.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bn_extra/convert.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/buf/buf.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/cipher_extra.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/derive_key.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_des.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_null.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_rc2.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_rc4.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/printf.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/socket.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bn_extra/convert.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/buf/buf.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/cipher_extra.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/derive_key.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_des.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_null.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_rc2.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_rc4.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/conf/conf.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/conf/conf_def.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_intel.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/des/des.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/conf/conf.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_intel.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/des/des.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/des/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/digest_extra/digest_extra.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/dsa/dsa.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/err/err.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/evp.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_ctx.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/digest_extra/digest_extra.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/dsa/dsa.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/err/err.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/evp.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_ctx.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/sign.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/ex_data.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/add.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/bn.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/bytes.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/cmp.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/div.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/exponentiation.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/generic.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/mul.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/prime.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/random.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/shift.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/cipher.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/sign.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/ex_data.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/add.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/bn.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/bytes.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/cmp.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/div.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/exponentiation.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/generic.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/mul.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/prime.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/random.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/shift.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/cipher.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/check.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/dh.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/digest.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/digests.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/check.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/dh.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/digest.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/digests.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digest/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hmac/hmac.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/md4/md4.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/md5/md5.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/blinding.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hmac/hmac.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/blinding.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha256.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha512.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha1.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha256.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/sha512.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/internal.h FILE: ../../../flutter/third_party/boringssl/src/crypto/lhash/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/lhash/lhash.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/mem.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/obj/obj.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/obj/obj_xref.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_all.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_info.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_lib.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_oth.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_pk8.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_pkey.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rc4/rc4.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/lhash/lhash.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/md4/md4.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/md5/md5.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/mem.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/obj/obj.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/obj/obj_xref.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_all.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_info.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_lib.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_oth.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_pk8.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_pkey.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rc4/rc4.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_crypt.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/stack/stack.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/thread.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/a_digest.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/a_sign.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/a_verify.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/algorithm.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/asn1_gen.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/by_dir.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/by_file.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/i2d_pr.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/name_print.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/t_crl.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/t_req.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/t_x509.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/t_x509a.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_att.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_cmp.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_d2.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_def.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_ext.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_lu.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_obj.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_req.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_set.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_txt.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_v3.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_vfy.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509name.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509rset.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_all.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_attrib.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_crl.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_exten.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_name.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_pubkey.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_req.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_sig.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_spki.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_val.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_x509.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/bio/base64_bio.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/blowfish/blowfish.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/cast/cast.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/cast/cast_tables.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_crypt.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/stack/stack.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/thread.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/a_digest.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/a_sign.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/a_verify.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/algorithm.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/asn1_gen.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/by_dir.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/by_file.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/i2d_pr.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/name_print.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/t_crl.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/t_req.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/t_x509.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/t_x509a.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_att.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_cmp.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_d2.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_def.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_ext.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_lu.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_obj.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_req.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_set.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_txt.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_v3.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_vfy.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509name.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509rset.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_all.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_attrib.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_crl.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_exten.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_name.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_pubkey.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_req.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_sig.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_spki.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_val.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_x509.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/bio/base64_bio.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/blowfish/blowfish.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/cast/cast.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/cast/cast_tables.cc FILE: ../../../flutter/third_party/boringssl/src/decrepit/cast/internal.h -FILE: ../../../flutter/third_party/boringssl/src/decrepit/des/cfb64ede.c +FILE: ../../../flutter/third_party/boringssl/src/decrepit/des/cfb64ede.cc FILE: ../../../flutter/third_party/boringssl/src/decrepit/macros.h -FILE: ../../../flutter/third_party/boringssl/src/decrepit/rc4/rc4_decrepit.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/ripemd/ripemd.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/rsa/rsa_decrepit.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/ssl/ssl_decrepit.c +FILE: ../../../flutter/third_party/boringssl/src/decrepit/rc4/rc4_decrepit.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/ripemd/ripemd.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/rsa/rsa_decrepit.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/ssl/ssl_decrepit.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/asn1.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/base64.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/bio.h @@ -32191,11 +32189,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/jacobi.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/sqrt.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/jacobi.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/sqrt.cc.inc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/jacobi.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/sqrt.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/jacobi.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/sqrt.cc.inc ---------------------------------------------------------------------------------------------------- Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. @@ -32246,18 +32244,18 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ex_data.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/prime.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/random.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ex_data.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/prime.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/random.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/internal.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/base.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ex_data.h TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/ex_data.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/prime.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/random.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/ex_data.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/prime.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/random.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/internal.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/base.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ex_data.h @@ -32311,18 +32309,18 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_all.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/dh/dh_decrepit.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/dsa/dsa_decrepit.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_all.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/dh/dh_decrepit.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/dsa/dsa_decrepit.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ssl3.h ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/handshake.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/s3_both.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/s3_pkt.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/tls_record.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_all.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/dh/dh_decrepit.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/dsa/dsa_decrepit.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_all.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/dh/dh_decrepit.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/dsa/dsa_decrepit.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ssl3.h FILE: ../../../flutter/third_party/boringssl/src/ssl/handshake.cc FILE: ../../../flutter/third_party/boringssl/src/ssl/s3_both.cc @@ -32378,9 +32376,9 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/pair.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/pair.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/pair.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/pair.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. @@ -32431,9 +32429,9 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/ctx.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/ctx.cc.inc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/ctx.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/ctx.cc.inc ---------------------------------------------------------------------------------------------------- Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved. @@ -32484,12 +32482,12 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ecdsa_extra/ecdsa_asn1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ecdsa_extra/ecdsa_asn1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ecdsa.h TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/ecdsa_extra/ecdsa_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/ecdsa_extra/ecdsa_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.cc.inc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ecdsa.h ---------------------------------------------------------------------------------------------------- Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. @@ -32541,28 +32539,28 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/exponentiation.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_key.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_montgomery.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/exponentiation.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_key.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_montgomery.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/oct.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/wnaf.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/oct.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/wnaf.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ec.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ec_key.h ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/d1_both.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/d1_pkt.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/dtls_record.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/exponentiation.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_key.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_montgomery.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/exponentiation.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_key.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_montgomery.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/oct.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/wnaf.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/oct.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/wnaf.cc.inc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ec.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ec_key.h FILE: ../../../flutter/third_party/boringssl/src/ssl/d1_both.cc @@ -32618,20 +32616,20 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/err/err.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/err/err.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/blinding.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/blinding.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/bn.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/err.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/tls1.h ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/d1_srtp.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/ssl_session.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/err/err.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/err/err.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/blinding.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/blinding.cc.inc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/bn.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/err.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/tls1.h @@ -32687,8 +32685,8 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/tls/kdf.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/ssl/ssl_decrepit.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/tls/kdf.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/ssl/ssl_decrepit.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ssl.h ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/extensions.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/handshake_client.cc @@ -32703,8 +32701,8 @@ ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/ssl_transcript.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/ssl_x509.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/t1_enc.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/tls/kdf.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/ssl/ssl_decrepit.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/tls/kdf.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/ssl/ssl_decrepit.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ssl.h FILE: ../../../flutter/third_party/boringssl/src/ssl/extensions.cc FILE: ../../../flutter/third_party/boringssl/src/ssl/handshake_client.cc @@ -32821,46 +32819,46 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/pbkdf.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/pbkdf.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/p5_pbev2.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/pkcs8.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/pkcs8_x509.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_akey.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_akeya.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_bcons.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_bitst.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_enum.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_extku.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ia5.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_info.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_lib.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_prn.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_skey.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_trs.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509spki.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_x509a.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/p5_pbev2.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/pkcs8.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/pkcs8_x509.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_akey.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_akeya.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_bcons.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_bitst.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_enum.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_extku.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ia5.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_info.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_lib.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_prn.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_skey.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_trs.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509spki.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_x509a.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/pkcs8.h TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/pbkdf.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/pbkdf.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/p5_pbev2.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/pkcs8.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/pkcs8_x509.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_akey.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_akeya.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_bcons.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_bitst.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_enum.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_extku.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ia5.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_info.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_lib.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_prn.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_skey.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_trs.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509spki.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_x509a.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/p5_pbev2.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/pkcs8.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs8/pkcs8_x509.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_akey.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_akeya.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_bcons.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_bitst.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_enum.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_extku.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ia5.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_info.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_lib.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_prn.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_skey.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_trs.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509spki.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_x509a.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/pkcs8.h ---------------------------------------------------------------------------------------------------- Copyright (c) 1999 The OpenSSL Project. All rights reserved. @@ -32946,9 +32944,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_conf.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_conf.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_conf.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_conf.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. @@ -32999,11 +32997,11 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_alt.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_utl.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_alt.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_utl.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_alt.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_utl.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_alt.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_utl.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved. @@ -33055,15 +33053,15 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/ext_dat.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_cpols.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_int.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_purp.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_cpols.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_int.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_purp.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/x509v3_errors.h TYPE: LicenseType.bsd FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/ext_dat.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_cpols.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_int.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_purp.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_cpols.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_int.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_purp.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/x509v3_errors.h ---------------------------------------------------------------------------------------------------- Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. @@ -33223,11 +33221,11 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_crld.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_genn.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_crld.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_genn.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_crld.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_genn.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_crld.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_genn.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved. @@ -33418,9 +33416,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_algor.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x_algor.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_algor.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x_algor.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2000 The OpenSSL Project. All rights reserved. @@ -33471,12 +33469,12 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ecdh.h TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.cc.inc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ecdh.h ---------------------------------------------------------------------------------------------------- Copyright (c) 2000-2002 The OpenSSL Project. All rights reserved. @@ -33528,9 +33526,9 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/ec_asn1.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/ec_asn1.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/ec_asn1.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/ec_asn1.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2000-2003 The OpenSSL Project. All rights reserved. @@ -33620,14 +33618,14 @@ authorization of the copyright holder. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dh_extra/dh_asn1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dsa/dsa_asn1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_asn1.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dh_extra/dh_asn1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dsa/dsa_asn1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_asn1.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/asn1t.h TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/dh_extra/dh_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/dsa/dsa_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_asn1.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/dh_extra/dh_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/dsa/dsa_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_asn1.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/asn1t.h ---------------------------------------------------------------------------------------------------- Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. @@ -33757,13 +33755,13 @@ authorization of the copyright holder. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_x509.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_xaux.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509cset.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_x509.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_xaux.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509cset.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_x509.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_xaux.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509cset.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_x509.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pem/pem_xaux.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509cset.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2001 The OpenSSL Project. All rights reserved. @@ -33938,11 +33936,11 @@ authorization of the copyright holder. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/key_wrap.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/e_aes.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/key_wrap.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/e_aes.cc.inc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/key_wrap.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/e_aes.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/key_wrap.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/e_aes.cc.inc ---------------------------------------------------------------------------------------------------- Copyright (c) 2001-2011 The OpenSSL Project. All rights reserved. @@ -34717,12 +34715,12 @@ freely, subject to the following restrictions: ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/mode_wrappers.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/mode_wrappers.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/aes.h TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/mode_wrappers.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/mode_wrappers.cc.inc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/aes.h ---------------------------------------------------------------------------------------------------- Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved. @@ -35342,13 +35340,13 @@ authorization of the copyright holder. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ncons.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_pcons.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_pmaps.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ncons.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_pcons.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_pmaps.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ncons.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_pcons.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_pmaps.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ncons.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_pcons.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_pmaps.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2003 The OpenSSL Project. All rights reserved. @@ -35673,9 +35671,9 @@ authorization of the copyright holder. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_vpm.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_vpm.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_vpm.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/x509_vpm.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2004 The OpenSSL Project. All rights reserved. @@ -36046,9 +36044,9 @@ authorization of the copyright holder. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/padding.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/padding.cc.inc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/padding.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rsa/padding.cc.inc ---------------------------------------------------------------------------------------------------- Copyright (c) 2005 The OpenSSL Project. All rights reserved. @@ -36100,22 +36098,22 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dsa_asn1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ec.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ec_asn1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_rsa.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_rsa_asn1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/print.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/rsa_pss.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dsa_asn1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ec.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ec_asn1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_rsa.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_rsa_asn1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/print.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/rsa_pss.cc TYPE: LicenseType.bsd FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dsa_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ec.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ec_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_rsa.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_rsa_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/print.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/rsa_pss.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dsa_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ec.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ec_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_rsa.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_rsa_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/print.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/rsa_pss.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2006 The OpenSSL Project. All rights reserved. @@ -36166,9 +36164,9 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digestsign/digestsign.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digestsign/digestsign.cc.inc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digestsign/digestsign.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/digestsign/digestsign.cc.inc ---------------------------------------------------------------------------------------------------- Copyright (c) 2006,2007 The OpenSSL Project. All rights reserved. @@ -36539,21 +36537,21 @@ SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/e_aesccm.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/cbc.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/cfb.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/ctr.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/e_aesccm.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/cbc.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/cfb.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/ctr.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/ofb.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/ofb.cc.inc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/e_aesccm.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/cbc.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/cfb.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/ctr.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/e_aesccm.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/cbc.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/cfb.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/ctr.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/ofb.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/ofb.cc.inc ---------------------------------------------------------------------------------------------------- Copyright (c) 2008 The OpenSSL Project. All rights reserved. @@ -37236,9 +37234,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cmac/cmac.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cmac/cmac.cc.inc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cmac/cmac.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cmac/cmac.cc.inc ---------------------------------------------------------------------------------------------------- Copyright (c) 2010 The OpenSSL Project. All rights reserved. @@ -37436,9 +37434,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dh_extra/params.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dh_extra/params.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/dh_extra/params.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/dh_extra/params.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2011 The OpenSSL Project. All rights reserved. @@ -37489,9 +37487,9 @@ OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/xts/xts.c +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/xts/xts.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/decrepit/xts/xts.c +FILE: ../../../flutter/third_party/boringssl/src/decrepit/xts/xts.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2011 The OpenSSL Project. All rights reserved. @@ -37677,9 +37675,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/tls_cbc.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/tls_cbc.cc TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/tls_cbc.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/tls_cbc.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2012 The OpenSSL Project. All rights reserved. @@ -38152,25 +38150,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/socket_helper.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/ber.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/cbb.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/cbs.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bio/socket_helper.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/ber.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/cbb.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/cbs.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/chacha/chacha.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_chacha20poly1305.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_tls.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/crypto.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/engine/engine.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/aead.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hkdf/hkdf.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/rand.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/urandom.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/pkcs7.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_arm.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_vec.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/windows.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/chacha/chacha.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_chacha20poly1305.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_tls.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/crypto.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/engine/engine.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/aead.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hkdf/hkdf.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/rand.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/pkcs7.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_arm.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_vec.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/urandom.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/windows.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/aead.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/bytestring.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/chacha.h @@ -38199,25 +38197,25 @@ ORIGIN: ../../../flutter/third_party/boringssl/src/tool/tool.cc ORIGIN: ../../../flutter/third_party/boringssl/src/tool/transport_common.cc ORIGIN: ../../../flutter/third_party/boringssl/src/tool/transport_common.h TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/socket_helper.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/ber.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/cbb.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/cbs.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/bio/socket_helper.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/ber.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/cbb.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/cbs.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/chacha/chacha.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_chacha20poly1305.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_tls.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/crypto.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/engine/engine.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/aead.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hkdf/hkdf.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/rand.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/urandom.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/pkcs7.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_arm.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_vec.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/windows.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/chacha/chacha.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_chacha20poly1305.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_tls.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/crypto.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/engine/engine.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cipher/aead.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/hkdf/hkdf.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/rand.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/pkcs7.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_arm.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_vec.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/urandom.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/windows.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/aead.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/bytestring.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/chacha.h @@ -38580,17 +38578,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bn_extra/bn_asn1.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bn_extra/bn_asn1.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/conf/internal.h ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/asm/x25519-asm-arm.S -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p224-64.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/util.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p224-64.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/util.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/refcount.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/thread_none.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/thread_pthread.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/thread_win.c -ORIGIN: ../../../flutter/third_party/boringssl/src/gen/crypto/err_data.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/refcount.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/thread_none.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/thread_pthread.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/thread_win.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/gen/crypto/err_data.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/buffer.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/cmac.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/curve25519.h @@ -38604,17 +38602,17 @@ ORIGIN: ../../../flutter/third_party/boringssl/src/tool/generate_ed25519.cc ORIGIN: ../../../flutter/third_party/boringssl/src/tool/genrsa.cc ORIGIN: ../../../flutter/third_party/boringssl/src/tool/rand.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/bn_extra/bn_asn1.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/bn_extra/bn_asn1.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/conf/internal.h FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/asm/x25519-asm-arm.S -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p224-64.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/util.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p224-64.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/util.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/refcount.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/thread_none.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/thread_pthread.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/thread_win.c -FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/err_data.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/refcount.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/thread_none.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/thread_pthread.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/thread_win.cc +FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/err_data.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/buffer.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/cmac.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/curve25519.h @@ -38822,20 +38820,20 @@ freely, subject to the following restrictions: ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/asn1_compat.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_linux.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_linux.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/spake25519.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/polyval.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/asn1_compat.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_linux.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_linux.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/spake25519.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/polyval.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/obj/objects.go ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/poly1305/internal.h ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pool/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pool/pool.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/deterministic.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/evp/dss1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/evp/evp_do_all.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/obj/obj_decrepit.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/x509/x509_decrepit.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pool/pool.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/deterministic.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/evp/dss1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/evp/evp_do_all.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/obj/obj_decrepit.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/x509/x509_decrepit.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/asn1_mac.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/obj_mac.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/pool.h @@ -38844,20 +38842,20 @@ ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/tls13_client.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/tls13_enc.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/tls13_server.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/asn1_compat.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_linux.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_linux.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/spake25519.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/polyval.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/asn1_compat.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_linux.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_linux.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/spake25519.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/polyval.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/obj/objects.go FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/internal.h FILE: ../../../flutter/third_party/boringssl/src/crypto/pool/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/pool/pool.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/deterministic.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/evp/dss1.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/evp/evp_do_all.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/obj/obj_decrepit.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/x509/x509_decrepit.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/pool/pool.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/deterministic.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/evp/dss1.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/evp/evp_do_all.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/obj/obj_decrepit.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/x509/x509_decrepit.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/asn1_mac.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/obj_mac.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/pool.h @@ -38911,44 +38909,44 @@ freely, subject to the following restrictions: ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_aesctrhmac.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_aesgcmsiv.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_aesctrhmac.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_aesgcmsiv.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/err/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ed25519.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ed25519_asn1.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ed25519.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ed25519_asn1.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bcm.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bcm.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/delocate.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/ctrdrbg.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/self_check/fips.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/self_check/self_check.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/ctrdrbg.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/self_check/fips.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/self_check/self_check.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/pkcs7_x509.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/forkunsafe.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/rand_extra.c -ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/cfb/cfb.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/pkcs7_x509.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/forkunsafe.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/rand_extra.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/decrepit/cfb/cfb.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/is_boringssl.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/span.h ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/ssl_versions.cc ORIGIN: ../../../flutter/third_party/boringssl/src/tool/file.cc ORIGIN: ../../../flutter/third_party/boringssl/src/tool/sign.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_aesctrhmac.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_aesgcmsiv.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_aesctrhmac.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cipher_extra/e_aesgcmsiv.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/err/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ed25519.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ed25519_asn1.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ed25519.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_ed25519_asn1.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bcm.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bcm.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/delocate.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/ctrdrbg.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/self_check/fips.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/self_check/self_check.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/ctrdrbg.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/self_check/fips.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/self_check/self_check.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/pkcs7_x509.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/forkunsafe.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/rand_extra.c -FILE: ../../../flutter/third_party/boringssl/src/decrepit/cfb/cfb.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/pkcs7/pkcs7_x509.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/forkunsafe.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/rand_extra.cc +FILE: ../../../flutter/third_party/boringssl/src/decrepit/cfb/cfb.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/is_boringssl.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/span.h FILE: ../../../flutter/third_party/boringssl/src/ssl/ssl_versions.cc @@ -39135,38 +39133,38 @@ IN THE MATERIALS. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/unicode.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bytestring/unicode.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/chacha/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_fuchsia.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_fuchsia.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_linux.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/div_extra.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd_extra.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/felem.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/scalar.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple_mul.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/md5/internal.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/div_extra.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd_extra.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/felem.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/scalar.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple_mul.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/internal.h ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/tls/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/hrss/hrss.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/hrss/hrss.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/hrss/internal.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/md5/internal.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/e_os2.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/hrss.h ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/handoff.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/unicode.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/bytestring/unicode.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/chacha/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_fuchsia.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_fuchsia.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_linux.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/div_extra.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd_extra.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/felem.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/scalar.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple_mul.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/md5/internal.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/div_extra.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/gcd_extra.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/felem.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/scalar.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple_mul.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/sha/internal.h FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/tls/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/hrss/hrss.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/hrss/hrss.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/hrss/internal.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/md5/internal.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/e_os2.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/hrss.h FILE: ../../../flutter/third_party/boringssl/src/ssl/handoff.cc @@ -39188,9 +39186,9 @@ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_win.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_win.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_win.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_win.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2018, Google Inc. Copyright (c) 2020, Arm Ltd. @@ -39275,26 +39273,26 @@ SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/ec_derive.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_x25519.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_x25519_asn1.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes_nohw.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/fips_shared_support.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/siphash/siphash.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/ec_derive.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_x25519.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_x25519_asn1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes_nohw.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/fips_shared_support.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/siphash/siphash.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/trust_token/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/trust_token/trust_token.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/trust_token/trust_token.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/siphash.h TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/ec_derive.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_x25519.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_x25519_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes_nohw.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/fips_shared_support.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/siphash/siphash.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/ec_derive.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_x25519.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_x25519_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes_nohw.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/fips_shared_support.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/siphash/siphash.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/trust_token/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/trust_token/trust_token.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/trust_token/trust_token.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/siphash.h ---------------------------------------------------------------------------------------------------- Copyright (c) 2019, Google Inc. @@ -39433,40 +39431,38 @@ MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519_tables.h ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/internal.h ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/dsa/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/hash_to_curve.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/hash_to_curve.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256_table.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/fork_detect.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/fork_detect.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/getrandom_fillin.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/hpke/hpke.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/passive.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/trust_token/pmbtoken.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/trust_token/voprf.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/hpke/hpke.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/fork_detect.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/getrandom_fillin.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/passive.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/trust_token/pmbtoken.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/trust_token/voprf.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/hpke.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/trust_token.h ORIGIN: ../../../flutter/third_party/boringssl/src/tool/fd.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519_tables.h FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/internal.h FILE: ../../../flutter/third_party/boringssl/src/crypto/dsa/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/hash_to_curve.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/hash_to_curve.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/ec_extra/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256_table.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/fork_detect.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/fork_detect.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/rand/getrandom_fillin.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/hpke/hpke.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/passive.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/trust_token/pmbtoken.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/trust_token/voprf.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/hpke/hpke.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/fork_detect.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/getrandom_fillin.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/passive.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/trust_token/pmbtoken.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/trust_token/voprf.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/hpke.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/trust_token.h FILE: ../../../flutter/third_party/boringssl/src/tool/fd.cc @@ -39674,18 +39670,18 @@ SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/blake2/blake2.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/blake2/blake2.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/blake2/blake2b256_tests.txt -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_apple.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_apple.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdsa/internal.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/blake2.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/x509_vfy.h ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/encrypted_client_hello.cc ORIGIN: ../../../flutter/third_party/boringssl/src/tool/generate_ech.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/blake2/blake2.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/blake2/blake2.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/blake2/blake2b256_tests.txt -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_apple.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_apple.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdsa/internal.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/blake2.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/x509_vfy.h @@ -39801,20 +39797,20 @@ SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/posix_time.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_freebsd.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_hkdf.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/asn1/posix_time.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_freebsd.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_hkdf.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/policy.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/policy.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ctrdrbg.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/kdf.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/posix_time.h TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/posix_time.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_freebsd.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_hkdf.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/asn1/posix_time.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_arm_freebsd.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_hkdf.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/dh/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/policy.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/policy.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ctrdrbg.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/kdf.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/posix_time.h @@ -39836,9 +39832,9 @@ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_openbsd.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_openbsd.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_openbsd.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_openbsd.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2022, Robert Nagy @@ -39897,39 +39893,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_sysreg.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519_64_adx.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_sysreg.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519_64_adx.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/builtin_curves.h ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/keccak/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/keccak/keccak.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/keccak/keccak.cc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/kyber/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/kyber/kyber.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/getentropy.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/ios.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/trusty.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/kyber/kyber.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/mlkem/internal.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/getentropy.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/ios.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/trusty.cc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/asm_base.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/experimental/kyber.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/pki/certificate.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/target.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/x509v3.h ORIGIN: ../../../flutter/third_party/boringssl/src/pki/certificate.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/pki/verify.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_sysreg.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519_64_adx.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_sysreg.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/curve25519/curve25519_64_adx.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/builtin_curves.h FILE: ../../../flutter/third_party/boringssl/src/crypto/keccak/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/keccak/keccak.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/keccak/keccak.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/kyber/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/kyber/kyber.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/getentropy.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/ios.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/trusty.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/kyber/kyber.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/internal.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/getentropy.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/ios.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/trusty.cc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/asm_base.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/experimental/kyber.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/pki/certificate.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/target.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/x509v3.h FILE: ../../../flutter/third_party/boringssl/src/pki/certificate.cc +FILE: ../../../flutter/third_party/boringssl/src/pki/verify.cc ---------------------------------------------------------------------------------------------------- Copyright (c) 2023, Google Inc. @@ -39948,39 +39948,35 @@ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/address.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/address.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/fors.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/fors.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/merkle.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/merkle.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/params.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/spx.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/spx_util.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/spx_util.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/thash.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/thash.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/wots.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/spx/wots.h -ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/experimental/spx.h +ORIGIN: ../../../flutter/third_party/boringssl/src/MODULE.bazel +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/bcm_support.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bcm_interface.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/sysrand_internal.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_extra.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/sha/sha1.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/sha/sha256.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/sha/sha512.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/mlkem.h +ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/pki/verify_error.h +ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/time.h +ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/ssl_credential.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/address.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/address.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/fors.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/fors.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/merkle.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/merkle.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/params.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/spx.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/spx_util.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/spx_util.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/thash.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/thash.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/wots.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/wots.h -FILE: ../../../flutter/third_party/boringssl/src/include/openssl/experimental/spx.h ----------------------------------------------------------------------------------------------------- -Copyright (c) 2023, Google LLC +FILE: ../../../flutter/third_party/boringssl/src/MODULE.bazel +FILE: ../../../flutter/third_party/boringssl/src/crypto/bcm_support.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bcm_interface.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/rand_extra/sysrand_internal.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_extra.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/sha/sha1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/sha/sha256.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/sha/sha512.cc +FILE: ../../../flutter/third_party/boringssl/src/include/openssl/mlkem.h +FILE: ../../../flutter/third_party/boringssl/src/include/openssl/pki/verify_error.h +FILE: ../../../flutter/third_party/boringssl/src/include/openssl/time.h +FILE: ../../../flutter/third_party/boringssl/src/ssl/ssl_credential.cc +---------------------------------------------------------------------------------------------------- +Copyright (c) 2024, Google Inc. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -39997,17 +39993,43 @@ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/MODULE.bazel -ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/pki/verify_error.h -ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/time.h -ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/ssl_credential.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/mldsa/internal.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/mldsa/mldsa.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/address.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/fors.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/fors.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/internal.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/merkle.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/merkle.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/params.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/slhdsa.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/thash.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/thash.h +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/wots.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/wots.h +ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/bcm_public.h +ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/mldsa.h +ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/slhdsa.h TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/MODULE.bazel -FILE: ../../../flutter/third_party/boringssl/src/include/openssl/pki/verify_error.h -FILE: ../../../flutter/third_party/boringssl/src/include/openssl/time.h -FILE: ../../../flutter/third_party/boringssl/src/ssl/ssl_credential.cc ----------------------------------------------------------------------------------------------------- -Copyright (c) 2024, Google Inc. +FILE: ../../../flutter/third_party/boringssl/src/crypto/mldsa/internal.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/mldsa/mldsa.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/address.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/fors.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/fors.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/internal.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/merkle.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/merkle.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/params.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/slhdsa.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/thash.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/thash.h +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/wots.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/wots.h +FILE: ../../../flutter/third_party/boringssl/src/include/openssl/bcm_public.h +FILE: ../../../flutter/third_party/boringssl/src/include/openssl/mldsa.h +FILE: ../../../flutter/third_party/boringssl/src/include/openssl/slhdsa.h +---------------------------------------------------------------------------------------------------- +Copyright (c) 2024, Google LLC Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -40385,9 +40407,9 @@ THE SOFTWARE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ocsp.c (with ../../../flutter/third_party/boringssl/src/LICENSE) +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ocsp.cc (with ../../../flutter/third_party/boringssl/src/LICENSE) TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ocsp.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ocsp.cc ---------------------------------------------------------------------------------------------------- Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. @@ -40494,13 +40516,13 @@ license provided above. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_key.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_montgomery.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_key.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_montgomery.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/oct.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/wnaf.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/oct.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple.cc.inc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/wnaf.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ec.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ec_key.h ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/tls1.h @@ -40508,13 +40530,13 @@ ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/handshake_client.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/handshake_server.cc ORIGIN: ../../../flutter/third_party/boringssl/src/ssl/s3_lib.cc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_key.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_montgomery.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_key.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_montgomery.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/oct.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/wnaf.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/oct.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/simple.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/wnaf.cc.inc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ec.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ec_key.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/tls1.h @@ -40533,12 +40555,12 @@ license provided above. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.c + ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.c -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.c + ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.cc + ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.cc +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.cc.inc + ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/ecdh.h + ../../../flutter/third_party/boringssl/src/include/openssl/ecdh.h TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdh/ecdh.cc.inc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ecdh.h ---------------------------------------------------------------------------------------------------- Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. @@ -41137,9 +41159,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_print.c (with ../../../flutter/third_party/boringssl/src/LICENSE) +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_print.cc (with ../../../flutter/third_party/boringssl/src/LICENSE) TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_print.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_print.cc ---------------------------------------------------------------------------------------------------- Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved. @@ -41151,9 +41173,9 @@ https://www.openssl.org/source/license.html ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh.c (with ../../../flutter/third_party/boringssl/src/LICENSE) +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh.cc (with ../../../flutter/third_party/boringssl/src/LICENSE) TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh.cc ---------------------------------------------------------------------------------------------------- Copyright 2006-2019 The OpenSSL Project Authors. All Rights Reserved. @@ -41165,9 +41187,9 @@ https://www.openssl.org/source/license.html ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh_asn1.c (with ../../../flutter/third_party/boringssl/src/LICENSE) +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh_asn1.cc (with ../../../flutter/third_party/boringssl/src/LICENSE) TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh_asn1.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh_asn1.cc ---------------------------------------------------------------------------------------------------- Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved. @@ -42532,8 +42554,14 @@ ORIGIN: ../../../flutter/display_list/dl_storage.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_tile_mode.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_vertices.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_vertices.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/display_list/effects/color_sources/dl_color_color_source.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/display_list/effects/color_sources/dl_color_color_source.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/color_filters/dl_blend_color_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/color_filters/dl_blend_color_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/color_filters/dl_matrix_color_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/color_filters/dl_matrix_color_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/color_sources/dl_conical_gradient_color_source.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/color_sources/dl_conical_gradient_color_source.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/color_sources/dl_gradient_color_source_base.h + ../../../flutter/LICENSE @@ -42550,6 +42578,7 @@ ORIGIN: ../../../flutter/display_list/effects/color_sources/dl_sweep_gradient_co ORIGIN: ../../../flutter/display_list/effects/color_sources/dl_sweep_gradient_color_source.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_filter.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_color_filters.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_source.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_source.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_sources.h + ../../../flutter/LICENSE @@ -43077,6 +43106,8 @@ ORIGIN: ../../../flutter/impeller/entity/geometry/rect_geometry.cc + ../../../fl ORIGIN: ../../../flutter/impeller/entity/geometry/rect_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/round_rect_geometry.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/round_rect_geometry.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/geometry/round_superellipse_geometry.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/geometry/round_superellipse_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/superellipse_geometry.cc + ../../../flutter/LICENSE @@ -44565,9 +44596,11 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterOverl ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h + ../../../flutter/LICENSE @@ -44627,8 +44660,6 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/overlay_laye ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_pool.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h + ../../../flutter/LICENSE @@ -45026,6 +45057,8 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_private. ORIGIN: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_key_event.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_key_event.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_key_event_channel.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_key_event_channel.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_channel.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_channel.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_handler.cc + ../../../flutter/LICENSE @@ -45062,6 +45095,7 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_pixel_buffer_texture_private.h ORIGIN: ../../../flutter/shell/platform/linux/fl_pixel_buffer_texture_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_platform_channel.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_platform_channel.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_platform_channel_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_platform_handler.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_platform_handler.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_platform_handler_test.cc + ../../../flutter/LICENSE @@ -45451,8 +45485,14 @@ FILE: ../../../flutter/display_list/dl_storage.h FILE: ../../../flutter/display_list/dl_tile_mode.h FILE: ../../../flutter/display_list/dl_vertices.cc FILE: ../../../flutter/display_list/dl_vertices.h -FILE: ../../../flutter/display_list/effects/color_sources/dl_color_color_source.cc -FILE: ../../../flutter/display_list/effects/color_sources/dl_color_color_source.h +FILE: ../../../flutter/display_list/effects/color_filters/dl_blend_color_filter.cc +FILE: ../../../flutter/display_list/effects/color_filters/dl_blend_color_filter.h +FILE: ../../../flutter/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.cc +FILE: ../../../flutter/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h +FILE: ../../../flutter/display_list/effects/color_filters/dl_matrix_color_filter.cc +FILE: ../../../flutter/display_list/effects/color_filters/dl_matrix_color_filter.h +FILE: ../../../flutter/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.cc +FILE: ../../../flutter/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h FILE: ../../../flutter/display_list/effects/color_sources/dl_conical_gradient_color_source.cc FILE: ../../../flutter/display_list/effects/color_sources/dl_conical_gradient_color_source.h FILE: ../../../flutter/display_list/effects/color_sources/dl_gradient_color_source_base.h @@ -45469,6 +45509,7 @@ FILE: ../../../flutter/display_list/effects/color_sources/dl_sweep_gradient_colo FILE: ../../../flutter/display_list/effects/color_sources/dl_sweep_gradient_color_source.h FILE: ../../../flutter/display_list/effects/dl_color_filter.cc FILE: ../../../flutter/display_list/effects/dl_color_filter.h +FILE: ../../../flutter/display_list/effects/dl_color_filters.h FILE: ../../../flutter/display_list/effects/dl_color_source.cc FILE: ../../../flutter/display_list/effects/dl_color_source.h FILE: ../../../flutter/display_list/effects/dl_color_sources.h @@ -45996,6 +46037,8 @@ FILE: ../../../flutter/impeller/entity/geometry/rect_geometry.cc FILE: ../../../flutter/impeller/entity/geometry/rect_geometry.h FILE: ../../../flutter/impeller/entity/geometry/round_rect_geometry.cc FILE: ../../../flutter/impeller/entity/geometry/round_rect_geometry.h +FILE: ../../../flutter/impeller/entity/geometry/round_superellipse_geometry.cc +FILE: ../../../flutter/impeller/entity/geometry/round_superellipse_geometry.h FILE: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.cc FILE: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.h FILE: ../../../flutter/impeller/entity/geometry/superellipse_geometry.cc @@ -47502,9 +47545,11 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlay FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h @@ -47564,8 +47609,6 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_pool.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h @@ -47976,6 +48019,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_private.h FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_test.cc FILE: ../../../flutter/shell/platform/linux/fl_key_event.cc FILE: ../../../flutter/shell/platform/linux/fl_key_event.h +FILE: ../../../flutter/shell/platform/linux/fl_key_event_channel.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_event_channel.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_channel.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_channel.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_handler.cc @@ -48012,6 +48057,7 @@ FILE: ../../../flutter/shell/platform/linux/fl_pixel_buffer_texture_private.h FILE: ../../../flutter/shell/platform/linux/fl_pixel_buffer_texture_test.cc FILE: ../../../flutter/shell/platform/linux/fl_platform_channel.cc FILE: ../../../flutter/shell/platform/linux/fl_platform_channel.h +FILE: ../../../flutter/shell/platform/linux/fl_platform_channel_test.cc FILE: ../../../flutter/shell/platform/linux/fl_platform_handler.cc FILE: ../../../flutter/shell/platform/linux/fl_platform_handler.h FILE: ../../../flutter/shell/platform/linux/fl_platform_handler_test.cc @@ -48364,10 +48410,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.c (with ../../../flutter/third_party/boringssl/src/LICENSE) +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.cc.inc (with ../../../flutter/third_party/boringssl/src/LICENSE) ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.h (with ../../../flutter/third_party/boringssl/src/LICENSE) TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.h ---------------------------------------------------------------------------------------------------- Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved. @@ -48864,10 +48910,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.c (with ../../../flutter/third_party/boringssl/src/LICENSE) +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.cc.inc (with ../../../flutter/third_party/boringssl/src/LICENSE) ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.h (with ../../../flutter/third_party/boringssl/src/LICENSE) TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.h ---------------------------------------------------------------------------------------------------- Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved. @@ -49469,9 +49515,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/scrypt.c (with ../../../flutter/third_party/boringssl/src/LICENSE) +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/evp/scrypt.cc (with ../../../flutter/third_party/boringssl/src/LICENSE) TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/scrypt.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/scrypt.cc ---------------------------------------------------------------------------------------------------- Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. @@ -49483,9 +49529,9 @@ https://www.openssl.org/source/license.html ==================================================================================================== LIBRARY: boringssl -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery_inv.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery_inv.cc.inc TYPE: LicenseType.unknown -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery_inv.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/montgomery_inv.cc.inc ---------------------------------------------------------------------------------------------------- Copyright 2016 Brian Smith. @@ -54031,11 +54077,11 @@ found in the LICENSE file ==================================================================================================== LIBRARY: boringssl ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/service_indicator/internal.h -ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/service_indicator/service_indicator.c +ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/service_indicator/service_indicator.cc.inc ORIGIN: ../../../flutter/third_party/boringssl/src/include/openssl/service_indicator.h TYPE: LicenseType.unknown FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/service_indicator/internal.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/service_indicator/service_indicator.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/service_indicator/service_indicator.cc.inc FILE: ../../../flutter/third_party/boringssl/src/include/openssl/service_indicator.h ---------------------------------------------------------------------------------------------------- Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -57818,6 +57864,9 @@ LIBRARY: boringssl ORIGIN: ../../../flutter/third_party/boringssl/src/LICENSE TYPE: LicenseType.openssl FILE: ../../../flutter/third_party/boringssl/src/.bazelignore +FILE: ../../../flutter/third_party/boringssl/src/.bcr/metadata.template.json +FILE: ../../../flutter/third_party/boringssl/src/.bcr/presubmit.yml +FILE: ../../../flutter/third_party/boringssl/src/.bcr/source.template.json FILE: ../../../flutter/third_party/boringssl/src/MODULE.bazel.lock FILE: ../../../flutter/third_party/boringssl/src/PrivacyInfo.xcprivacy FILE: ../../../flutter/third_party/boringssl/src/build.json @@ -57847,13 +57896,13 @@ FILE: ../../../flutter/third_party/boringssl/src/crypto/err/trust_token.errordat FILE: ../../../flutter/third_party/boringssl/src/crypto/err/x509.errordata FILE: ../../../flutter/third_party/boringssl/src/crypto/err/x509v3.errordata FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/evp_tests.txt -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh_asn1.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/scrypt.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/p_dh_asn1.cc +FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/scrypt.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/evp/scrypt_tests.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/aes/aes_tests.txt -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/asm/x86_64-gcc.c -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/asm/x86_64-gcc.cc.inc +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/bn/rsaz_exp.h FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cmac/cavp_3des_cmac_tests.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cmac/cavp_aes128_cmac_tests.txt @@ -57861,7 +57910,7 @@ FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cmac/cavp_aes FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/cmac/cavp_aes256_cmac_tests.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/ec_scalar_base_mult_tests.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz-table.h -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.cc.inc FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz.h FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ec/p256-nistz_tests.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt @@ -57870,7 +57919,6 @@ FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/fips_shared.l FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/intcheck1.png FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/intcheck2.png FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/intcheck3.png -FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/modes/gcm_tests.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/policydocs/BoringCrypto-Android-Security-Policy-20191020.docx!/[Content_Types].xml FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/policydocs/BoringCrypto-Android-Security-Policy-20191020.docx!/_rels/.rels FILE: ../../../flutter/third_party/boringssl/src/crypto/fipsmodule/policydocs/BoringCrypto-Android-Security-Policy-20191020.docx!/customXml/_rels/item1.xml.rels @@ -57989,15 +58037,30 @@ FILE: ../../../flutter/third_party/boringssl/src/crypto/hpke/hpke_test_vectors.t FILE: ../../../flutter/third_party/boringssl/src/crypto/hpke/test-vectors.json FILE: ../../../flutter/third_party/boringssl/src/crypto/keccak/keccak_tests.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/kyber/kyber_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mldsa/mldsa_nist_keygen_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mldsa/mldsa_nist_siggen_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem1024_decap_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem1024_encap_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem1024_keygen_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem1024_nist_decap_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem1024_nist_keygen_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem768_decap_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem768_encap_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem768_keygen_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem768_nist_decap_tests.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/mlkem/mlkem768_nist_keygen_tests.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/obj/obj_mac.num FILE: ../../../flutter/third_party/boringssl/src/crypto/obj/objects.txt FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_arm_asm.S FILE: ../../../flutter/third_party/boringssl/src/crypto/poly1305/poly1305_tests.txt -FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_print.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/rsa_extra/rsa_print.cc FILE: ../../../flutter/third_party/boringssl/src/crypto/siphash/siphash_tests.txt -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/spx_tests.txt -FILE: ../../../flutter/third_party/boringssl/src/crypto/spx/spx_tests_deterministic.txt -FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ocsp.c +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/slhdsa_keygen.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/slhdsa_prehash.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/slhdsa_siggen.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/slhdsa/slhdsa_sigver.txt +FILE: ../../../flutter/third_party/boringssl/src/crypto/x509/v3_ocsp.cc +FILE: ../../../flutter/third_party/boringssl/src/docs/releasing.md FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/aesni-gcm-x86_64-apple.S FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/aesni-gcm-x86_64-linux.S FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/aesni-gcm-x86_64-win.asm @@ -58048,12 +58111,6 @@ FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/ghashv8-armv7-linux.S FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/ghashv8-armv8-apple.S FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/ghashv8-armv8-linux.S FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/ghashv8-armv8-win.S -FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/md5-586-apple.S -FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/md5-586-linux.S -FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/md5-586-win.asm -FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/md5-x86_64-apple.S -FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/md5-x86_64-linux.S -FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/md5-x86_64-win.asm FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/p256-armv8-asm-apple.S FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/p256-armv8-asm-linux.S FILE: ../../../flutter/third_party/boringssl/src/gen/bcm/p256-armv8-asm-win.S @@ -58140,14 +58197,29 @@ FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/chacha20_poly1305_ar FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/chacha20_poly1305_x86_64-apple.S FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/chacha20_poly1305_x86_64-linux.S FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/chacha20_poly1305_x86_64-win.asm +FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/md5-586-apple.S +FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/md5-586-linux.S +FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/md5-586-win.asm +FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/md5-x86_64-apple.S +FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/md5-x86_64-linux.S +FILE: ../../../flutter/third_party/boringssl/src/gen/crypto/md5-x86_64-win.asm FILE: ../../../flutter/third_party/boringssl/src/gen/sources.json FILE: ../../../flutter/third_party/boringssl/src/go.mod FILE: ../../../flutter/third_party/boringssl/src/go.sum FILE: ../../../flutter/third_party/boringssl/src/include/openssl/pki/signature_verify_cache.h +FILE: ../../../flutter/third_party/boringssl/src/include/openssl/pki/verify.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ssl.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/ssl3.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/tls1.h FILE: ../../../flutter/third_party/boringssl/src/include/openssl/x509.h +FILE: ../../../flutter/third_party/boringssl/src/infra/config/generated/commit-queue.cfg +FILE: ../../../flutter/third_party/boringssl/src/infra/config/generated/cr-buildbucket.cfg +FILE: ../../../flutter/third_party/boringssl/src/infra/config/generated/luci-logdog.cfg +FILE: ../../../flutter/third_party/boringssl/src/infra/config/generated/luci-milo.cfg +FILE: ../../../flutter/third_party/boringssl/src/infra/config/generated/luci-notify.cfg +FILE: ../../../flutter/third_party/boringssl/src/infra/config/generated/luci-scheduler.cfg +FILE: ../../../flutter/third_party/boringssl/src/infra/config/generated/project.cfg +FILE: ../../../flutter/third_party/boringssl/src/infra/config/generated/realms.cfg FILE: ../../../flutter/third_party/boringssl/src/pki/cert_error_id.cc FILE: ../../../flutter/third_party/boringssl/src/pki/cert_error_id.h FILE: ../../../flutter/third_party/boringssl/src/pki/cert_error_params.cc diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index f1ba00e823091..09164b4b1c213 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: e698190fc2930d5fa6d31862a1561016 +Signature: 900dc900001d18e4977541a3c0a37c0f ==================================================================================================== LIBRARY: fuchsia_sdk @@ -13757,6 +13757,7 @@ ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.audio.signalprocessing/ ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.audio.signalprocessing/vendor_specific.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.audio/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.i2c.businfo/businfo.fidl + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.mailbox/mailbox.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.network/diagnostics.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.network/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.platform.bus/platform-bus.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -14100,6 +14101,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.audio.signalprocessing/ov FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.audio.signalprocessing/vendor_specific.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.audio/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.i2c.businfo/businfo.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.mailbox/mailbox.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.network/diagnostics.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.network/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.platform.bus/platform-bus.fidl @@ -14666,6 +14668,7 @@ LIBRARY: fuchsia_sdk ORIGIN: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/availability_levels.inc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/arch/riscv64/sysroot/include/zircon/availability_levels.inc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/availability_levels.inc + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/bind/fuchsia.mailbox/fuchsia.mailbox.bind + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/bind/fuchsia.regulator/fuchsia.regulator.bind + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/bind/fuchsia.spmi/fuchsia.spmi.bind + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.bredr/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -14674,6 +14677,7 @@ ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.le/iso.fidl + ../../.. ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.le/l2cap.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth/channel.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth/coding_format.fidl + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.component.runner/task_provider.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.component.sandbox/availability.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/introspector.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.device.fs/controller.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -14683,6 +14687,7 @@ ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.test/internal.fidl + ../. ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.bluetooth/emulator.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.bluetooth/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.light/metadata.fidl + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.mailbox/metadata.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pci/metadata.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pin/pin.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pinimpl/metadata.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -14690,6 +14695,7 @@ ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pinimpl/pin-impl.fidl + ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.platform.device/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.power/metadata.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.power/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.sdhci/sdhci.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.spmi/metadata.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.spmi/spmi.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.images2/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -14764,6 +14770,7 @@ 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 FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/availability_levels.inc +FILE: ../../../fuchsia/sdk/linux/bind/fuchsia.mailbox/fuchsia.mailbox.bind FILE: ../../../fuchsia/sdk/linux/bind/fuchsia.regulator/fuchsia.regulator.bind FILE: ../../../fuchsia/sdk/linux/bind/fuchsia.spmi/fuchsia.spmi.bind FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.bredr/overview.fidl @@ -14772,6 +14779,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.le/iso.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.le/l2cap.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth/channel.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth/coding_format.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component.runner/task_provider.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component.sandbox/availability.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/introspector.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.device.fs/controller.fidl @@ -14781,6 +14789,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.test/internal.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.bluetooth/emulator.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.bluetooth/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.light/metadata.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.mailbox/metadata.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pci/metadata.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pin/pin.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pinimpl/metadata.fidl @@ -14788,6 +14797,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.pinimpl/pin-impl.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.platform.device/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.power/metadata.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.power/overview.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.sdhci/sdhci.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.spmi/metadata.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.spmi/spmi.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.images2/overview.fidl diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f5788c559fbf6..c557c60594124 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 59342f4d7b5ab9509ab02179d966438f +Signature: 7f26d1550cef3678c79bfeed907ae5be ==================================================================================================== LIBRARY: etc1 @@ -402,6 +402,7 @@ FILE: ../../../flutter/third_party/skia/package-lock.json FILE: ../../../flutter/third_party/skia/relnotes/GpuStats.md FILE: ../../../flutter/third_party/skia/relnotes/GraphiteLogPriority.md FILE: ../../../flutter/third_party/skia/relnotes/SkColorSpaceMakeCICP.md +FILE: ../../../flutter/third_party/skia/relnotes/debugtrace.md FILE: ../../../flutter/third_party/skia/relnotes/precompilecontext.md FILE: ../../../flutter/third_party/skia/src/gpu/gpu_workaround_list.txt FILE: ../../../flutter/third_party/skia/src/ports/fontations/Cargo.toml @@ -9435,6 +9436,8 @@ ORIGIN: ../../../flutter/third_party/skia/src/codec/SkCrabbyAvifCodec.cpp + ../. ORIGIN: ../../../flutter/third_party/skia/src/codec/SkCrabbyAvifCodec.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/codec/SkJpegMetadataDecoderImpl.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/codec/SkJpegMetadataDecoderImpl.h + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/codec/SkPngCompositeChunkReader.cpp + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/codec/SkPngCompositeChunkReader.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/ganesh/gl/win/GrGLMakeWinInterface.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/ports/SkFontMgr_android_ndk.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/ports/SkFontMgr_fontations_empty.cpp + ../../../flutter/third_party/skia/LICENSE @@ -9457,6 +9460,8 @@ FILE: ../../../flutter/third_party/skia/src/codec/SkCrabbyAvifCodec.cpp FILE: ../../../flutter/third_party/skia/src/codec/SkCrabbyAvifCodec.h FILE: ../../../flutter/third_party/skia/src/codec/SkJpegMetadataDecoderImpl.cpp FILE: ../../../flutter/third_party/skia/src/codec/SkJpegMetadataDecoderImpl.h +FILE: ../../../flutter/third_party/skia/src/codec/SkPngCompositeChunkReader.cpp +FILE: ../../../flutter/third_party/skia/src/codec/SkPngCompositeChunkReader.h FILE: ../../../flutter/third_party/skia/src/gpu/ganesh/gl/win/GrGLMakeWinInterface.cpp FILE: ../../../flutter/third_party/skia/src/ports/SkFontMgr_android_ndk.cpp FILE: ../../../flutter/third_party/skia/src/ports/SkFontMgr_fontations_empty.cpp @@ -9523,6 +9528,7 @@ ORIGIN: ../../../flutter/third_party/skia/include/gpu/graphite/precompile/Precom ORIGIN: ../../../flutter/third_party/skia/include/gpu/graphite/precompile/PrecompileMaskFilter.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/gpu/graphite/precompile/PrecompileRuntimeEffect.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/gpu/graphite/precompile/PrecompileShader.h + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/modules/jsonreader/SkJSONReader.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_coretext.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_factory.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_harfbuzz.h + ../../../flutter/third_party/skia/LICENSE @@ -9650,6 +9656,7 @@ FILE: ../../../flutter/third_party/skia/include/gpu/graphite/precompile/Precompi FILE: ../../../flutter/third_party/skia/include/gpu/graphite/precompile/PrecompileMaskFilter.h FILE: ../../../flutter/third_party/skia/include/gpu/graphite/precompile/PrecompileRuntimeEffect.h FILE: ../../../flutter/third_party/skia/include/gpu/graphite/precompile/PrecompileShader.h +FILE: ../../../flutter/third_party/skia/modules/jsonreader/SkJSONReader.h FILE: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_coretext.h FILE: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_factory.h FILE: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_harfbuzz.h @@ -9787,6 +9794,8 @@ ORIGIN: ../../../flutter/third_party/skia/gm/smallcircles.cpp + ../../../flutter ORIGIN: ../../../flutter/third_party/skia/include/ports/SkFontMgr_android_ndk.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/codec/SkPngCodecBase.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/codec/SkPngCodecBase.h + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/encode/SkPngEncoderBase.cpp + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/encode/SkPngEncoderBase.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/vk/vulkanmemoryallocator/VulkanMemoryAllocatorPriv.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/sksl/transform/SkSLTransform.cpp + ../../../flutter/third_party/skia/LICENSE TYPE: LicenseType.bsd @@ -9794,6 +9803,8 @@ FILE: ../../../flutter/third_party/skia/gm/smallcircles.cpp FILE: ../../../flutter/third_party/skia/include/ports/SkFontMgr_android_ndk.h FILE: ../../../flutter/third_party/skia/src/codec/SkPngCodecBase.cpp FILE: ../../../flutter/third_party/skia/src/codec/SkPngCodecBase.h +FILE: ../../../flutter/third_party/skia/src/encode/SkPngEncoderBase.cpp +FILE: ../../../flutter/third_party/skia/src/encode/SkPngEncoderBase.h FILE: ../../../flutter/third_party/skia/src/gpu/vk/vulkanmemoryallocator/VulkanMemoryAllocatorPriv.h FILE: ../../../flutter/third_party/skia/src/sksl/transform/SkSLTransform.cpp ---------------------------------------------------------------------------------------------------- diff --git a/ci/pubspec.yaml b/ci/pubspec.yaml index b86c37bb84744..540d06b324852 100644 --- a/ci/pubspec.yaml +++ b/ci/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/display_list/BUILD.gn b/display_list/BUILD.gn index c1c9f94fcf772..3ed4e721bfc21 100644 --- a/display_list/BUILD.gn +++ b/display_list/BUILD.gn @@ -47,8 +47,14 @@ source_set("display_list") { "dl_tile_mode.h", "dl_vertices.cc", "dl_vertices.h", - "effects/color_sources/dl_color_color_source.cc", - "effects/color_sources/dl_color_color_source.h", + "effects/color_filters/dl_blend_color_filter.cc", + "effects/color_filters/dl_blend_color_filter.h", + "effects/color_filters/dl_linear_to_srgb_gamma_color_filter.cc", + "effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h", + "effects/color_filters/dl_matrix_color_filter.cc", + "effects/color_filters/dl_matrix_color_filter.h", + "effects/color_filters/dl_srgb_to_linear_gamma_color_filter.cc", + "effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h", "effects/color_sources/dl_conical_gradient_color_source.cc", "effects/color_sources/dl_conical_gradient_color_source.h", "effects/color_sources/dl_image_color_source.cc", @@ -63,8 +69,10 @@ source_set("display_list") { "effects/color_sources/dl_sweep_gradient_color_source.h", "effects/dl_color_filter.cc", "effects/dl_color_filter.h", + "effects/dl_color_filters.h", "effects/dl_color_source.cc", "effects/dl_color_source.h", + "effects/dl_color_sources.h", "effects/dl_image_filter.cc", "effects/dl_image_filter.h", "effects/dl_image_filters.h", diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index c26c9bd77e453..cfd1f6b66bbc5 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -518,7 +518,7 @@ TEST_F(DisplayListTest, BuildRestoresAttributes) { builder.Build(); check_defaults(builder, cull_rect); - receiver.setColorFilter(&kTestMatrixColorFilter1); + receiver.setColorFilter(kTestMatrixColorFilter1.get()); builder.Build(); check_defaults(builder, cull_rect); @@ -940,7 +940,7 @@ TEST_F(DisplayListTest, DisplayListSaveLayerBoundsWithAlphaFilter) { 0, 0, 0, 1, 0, }; // clang-format on - DlMatrixColorFilter base_color_filter(color_matrix); + auto base_color_filter = DlColorFilter::MakeMatrix(color_matrix); // clang-format off const float alpha_matrix[] = { 0, 0, 0, 0, 0, @@ -949,7 +949,7 @@ TEST_F(DisplayListTest, DisplayListSaveLayerBoundsWithAlphaFilter) { 0, 0, 0, 0, 1, }; // clang-format on - DlMatrixColorFilter alpha_color_filter(alpha_matrix); + auto alpha_color_filter = DlColorFilter::MakeMatrix(alpha_matrix); sk_sp sk_alpha_color_filter = SkColorFilters::Matrix(alpha_matrix); @@ -967,7 +967,7 @@ TEST_F(DisplayListTest, DisplayListSaveLayerBoundsWithAlphaFilter) { // Now checking that a normal color filter still produces rect bounds DisplayListBuilder builder(build_bounds); DlPaint save_paint; - save_paint.setColorFilter(&base_color_filter); + save_paint.setColorFilter(base_color_filter); builder.SaveLayer(&save_bounds, &save_paint); builder.DrawRect(rect, DlPaint()); builder.Restore(); @@ -999,7 +999,7 @@ TEST_F(DisplayListTest, DisplayListSaveLayerBoundsWithAlphaFilter) { // save layer that modifies an unbounded region DisplayListBuilder builder(build_bounds); DlPaint save_paint; - save_paint.setColorFilter(&alpha_color_filter); + save_paint.setColorFilter(alpha_color_filter); builder.SaveLayer(&save_bounds, &save_paint); builder.DrawRect(rect, DlPaint()); builder.Restore(); @@ -1012,7 +1012,7 @@ TEST_F(DisplayListTest, DisplayListSaveLayerBoundsWithAlphaFilter) { // to the behavior in the previous example DisplayListBuilder builder(build_bounds); DlPaint save_paint; - save_paint.setColorFilter(&alpha_color_filter); + save_paint.setColorFilter(alpha_color_filter); builder.SaveLayer(nullptr, &save_paint); builder.DrawRect(rect, DlPaint()); builder.Restore(); @@ -1367,7 +1367,7 @@ TEST_F(DisplayListTest, SaveLayerFalseWithSrcBlendSupportsGroupOpacity) { DisplayListBuilder builder; // This empty draw rect will not actually be inserted into the stream, // but the Src blend mode will be synchronized as an attribute. The - // saveLayer following it should not use that attribute to base its + // SaveLayer following it should not use that attribute to base its // decisions about group opacity and the draw rect after that comes // with its own compatible blend mode. builder.DrawRect(SkRect{0, 0, 0, 0}, @@ -1416,7 +1416,7 @@ TEST_F(DisplayListTest, SaveLayerBoundsSnapshotsImageFilter) { DlPaint save_paint; builder.SaveLayer(nullptr, &save_paint); builder.DrawRect(SkRect{50, 50, 100, 100}, DlPaint()); - // This image filter should be ignored since it was not set before saveLayer + // This image filter should be ignored since it was not set before SaveLayer // And the rect drawn with it will not contribute any more area to the bounds DlPaint draw_paint; draw_paint.setImageFilter(&kTestBlurImageFilter1); @@ -1668,7 +1668,7 @@ TEST_F(DisplayListTest, SaveLayerColorFilterDoesNotInheritOpacity) { DisplayListBuilder builder; DlPaint save_paint; save_paint.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255))); - save_paint.setColorFilter(&kTestMatrixColorFilter1); + save_paint.setColorFilter(kTestMatrixColorFilter1); builder.SaveLayer(nullptr, &save_paint); builder.DrawRect(SkRect{10, 10, 20, 20}, DlPaint()); builder.Restore(); @@ -1720,7 +1720,7 @@ TEST_F(DisplayListTest, SaveLayerColorFilterOnChildDoesNotInheritOpacity) { save_paint.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255))); builder.SaveLayer(nullptr, &save_paint); DlPaint draw_paint = save_paint; - draw_paint.setColorFilter(&kTestMatrixColorFilter1); + draw_paint.setColorFilter(kTestMatrixColorFilter1); builder.DrawRect(SkRect{10, 10, 20, 20}, draw_paint); builder.Restore(); @@ -2510,7 +2510,7 @@ TEST_F(DisplayListTest, RTreeOfSaveLayerFilterScene) { builder.DrawRect(SkRect{10, 10, 20, 20}, default_paint); builder.SaveLayer(nullptr, &filter_paint); // the following rectangle will be expanded to 50,50,60,60 - // by the saveLayer filter during the restore operation + // by the SaveLayer filter during the restore operation builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint); builder.Restore(); auto display_list = builder.Build(); @@ -2671,7 +2671,7 @@ TEST_F(DisplayListTest, RemoveUnnecessarySaveRestorePairsInSetPaint) { 0, 0, 0, 0, 1, }; // clang-format on - DlMatrixColorFilter alpha_color_filter(alpha_matrix); + auto alpha_color_filter = DlColorFilter::MakeMatrix(alpha_matrix); // Making sure hiding a problematic ColorFilter as an ImageFilter // will generate the same behavior as setting it as a ColorFilter @@ -3272,7 +3272,7 @@ TEST_F(DisplayListTest, RTreeOfClippedSaveLayerFilterScene) { builder.ClipRect(SkRect{50, 50, 60, 60}, ClipOp::kIntersect, false); builder.SaveLayer(nullptr, &filter_paint); // the following rectangle will be expanded to 23,23,87,87 - // by the saveLayer filter during the restore operation + // by the SaveLayer filter during the restore operation // but it will then be clipped to 50,50,60,60 builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint); builder.Restore(); @@ -3862,7 +3862,7 @@ TEST_F(DisplayListTest, TransformResetSaveLayerBoundsComputationOfSimpleRect) { builder.SaveLayer(nullptr, nullptr); builder.TransformReset(); builder.Scale(20.0f, 20.0f); - // Net local transform for saveLayer is Scale(2, 2) + // Net local transform for SaveLayer is Scale(2, 2) { // builder.DrawRect(rect, DlPaint()); } @@ -3957,7 +3957,7 @@ TEST_F(DisplayListTest, FloodingSaveLayerBoundsComputationOfSimpleRect) { SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); DlPaint save_paint; auto color_filter = - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kSrc); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc); ASSERT_TRUE(color_filter->modifies_transparent_black()); save_paint.setColorFilter(color_filter); SkRect clip_rect = rect.makeOutset(100.0f, 100.0f); @@ -3983,7 +3983,7 @@ TEST_F(DisplayListTest, NestedFloodingSaveLayerBoundsComputationOfSimpleRect) { SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); DlPaint save_paint; auto color_filter = - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kSrc); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc); ASSERT_TRUE(color_filter->modifies_transparent_black()); save_paint.setColorFilter(color_filter); SkRect clip_rect = rect.makeOutset(100.0f, 100.0f); @@ -4016,7 +4016,7 @@ TEST_F(DisplayListTest, SaveLayerBoundsComputationOfFloodingImageFilter) { SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); DlPaint draw_paint; auto color_filter = - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kSrc); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc); ASSERT_TRUE(color_filter->modifies_transparent_black()); auto image_filter = DlImageFilter::MakeColorFilter(color_filter); draw_paint.setImageFilter(image_filter); @@ -4043,7 +4043,7 @@ TEST_F(DisplayListTest, SaveLayerBoundsComputationOfFloodingColorFilter) { SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); DlPaint draw_paint; auto color_filter = - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kSrc); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc); ASSERT_TRUE(color_filter->modifies_transparent_black()); draw_paint.setColorFilter(color_filter); SkRect clip_rect = rect.makeOutset(100.0f, 100.0f); @@ -4233,7 +4233,7 @@ TEST_F(DisplayListTest, FloodingFilteredLayerPushesRestoreOpIndex) { 0.5f, 0.0f, 0.0f, 0.0f, 0.5f }; // clang-format on - auto color_filter = DlMatrixColorFilter::Make(matrix); + auto color_filter = DlColorFilter::MakeMatrix(matrix); save_paint.setImageFilter(DlImageFilter::MakeColorFilter(color_filter)); builder.SaveLayer(nullptr, &save_paint); int save_layer_id = DisplayListBuilderTestingLastOpIndex(builder); @@ -4451,7 +4451,7 @@ TEST_F(DisplayListTest, MaxBlendModeInsideComplexSaveLayers) { builder.Restore(); // Double check that kModulate is the max blend mode for the first - // saveLayer operations + // SaveLayer operations auto expect = std::max(DlBlendMode::kModulate, DlBlendMode::kSrc); ASSERT_EQ(expect, DlBlendMode::kModulate); @@ -4487,8 +4487,8 @@ TEST_F(DisplayListTest, BackdropDetectionSimpleSaveLayer) { auto dl = builder.Build(); EXPECT_TRUE(dl->root_has_backdrop_filter()); - // The saveLayer itself, though, does not have the contains backdrop - // flag set because its content does not contain a saveLayer with backdrop + // The SaveLayer itself, though, does not have the contains backdrop + // flag set because its content does not contain a SaveLayer with backdrop SAVE_LAYER_EXPECTOR(expector); expector.addExpectation( SaveLayerOptions::kNoAttributes.with_can_distribute_opacity()); @@ -5817,7 +5817,7 @@ TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; // clang-format on - auto unbounded_cf = DlMatrixColorFilter::Make(matrix); + auto unbounded_cf = DlColorFilter::MakeMatrix(matrix); // ColorFilter must modify transparent black to be "unbounded" ASSERT_TRUE(unbounded_cf->modifies_transparent_black()); auto unbounded_if = DlImageFilter::MakeColorFilter(unbounded_cf); @@ -5948,5 +5948,132 @@ TEST_F(DisplayListTest, RecordSingleLargeDisplayListOperation) { EXPECT_TRUE(!!builder.Build()); } +TEST_F(DisplayListTest, DisplayListDetectsRuntimeEffect) { + const auto runtime_effect = DlRuntimeEffect::MakeSkia( + SkRuntimeEffect::MakeForShader( + SkString("vec4 main(vec2 p) { return vec4(0); }")) + .effect); + auto color_source = DlColorSource::MakeRuntimeEffect( + runtime_effect, {}, std::make_shared>()); + auto image_filter = DlImageFilter::MakeRuntimeEffect( + runtime_effect, {}, std::make_shared>()); + + { + // Default - no runtime effects, supports group opacity + DisplayListBuilder builder; + DlPaint paint; + + builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint); + EXPECT_TRUE(builder.Build()->can_apply_group_opacity()); + } + + { + // Draw with RTE color source does not support group opacity + DisplayListBuilder builder; + DlPaint paint; + + paint.setColorSource(color_source); + builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint); + + EXPECT_FALSE(builder.Build()->can_apply_group_opacity()); + } + + { + // Draw with RTE image filter does not support group opacity + DisplayListBuilder builder; + DlPaint paint; + + paint.setImageFilter(image_filter); + builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint); + + EXPECT_FALSE(builder.Build()->can_apply_group_opacity()); + } + + { + // Draw with RTE color source inside SaveLayer does not support group + // opacity on the SaveLayer, but does support it on the DisplayList + DisplayListBuilder builder; + DlPaint paint; + + builder.SaveLayer(nullptr, nullptr); + paint.setColorSource(color_source); + builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint); + builder.Restore(); + + auto display_list = builder.Build(); + EXPECT_TRUE(display_list->can_apply_group_opacity()); + + SAVE_LAYER_EXPECTOR(expector); + expector.addExpectation([](const SaveLayerOptions& options) { + return !options.can_distribute_opacity(); + }); + display_list->Dispatch(expector); + } + + { + // Draw with RTE image filter inside SaveLayer does not support group + // opacity on the SaveLayer, but does support it on the DisplayList + DisplayListBuilder builder; + DlPaint paint; + + builder.SaveLayer(nullptr, nullptr); + paint.setImageFilter(image_filter); + builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint); + builder.Restore(); + + auto display_list = builder.Build(); + EXPECT_TRUE(display_list->can_apply_group_opacity()); + + SAVE_LAYER_EXPECTOR(expector); + expector.addExpectation([](const SaveLayerOptions& options) { + return !options.can_distribute_opacity(); + }); + display_list->Dispatch(expector); + } + + { + // Draw with RTE color source inside nested saveLayers does not support + // group opacity on the inner SaveLayer, but does support it on the + // outer SaveLayer and the DisplayList + DisplayListBuilder builder; + DlPaint paint; + + builder.SaveLayer(nullptr, nullptr); + + builder.SaveLayer(nullptr, nullptr); + paint.setColorSource(color_source); + builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint); + paint.setColorSource(nullptr); + builder.Restore(); + + builder.SaveLayer(nullptr, nullptr); + paint.setImageFilter(image_filter); + // Make sure these DrawRects are non-overlapping otherwise the outer + // SaveLayer and DisplayList will be incompatible due to overlaps + builder.DrawRect(DlRect::MakeLTRB(60, 60, 100, 100), paint); + paint.setImageFilter(nullptr); + builder.Restore(); + + builder.Restore(); + auto display_list = builder.Build(); + EXPECT_TRUE(display_list->can_apply_group_opacity()); + + SAVE_LAYER_EXPECTOR(expector); + expector.addExpectation([](const SaveLayerOptions& options) { + // outer SaveLayer supports group opacity + return options.can_distribute_opacity(); + }); + expector.addExpectation([](const SaveLayerOptions& options) { + // first inner SaveLayer does not support group opacity + return !options.can_distribute_opacity(); + }); + expector.addExpectation([](const SaveLayerOptions& options) { + // second inner SaveLayer does not support group opacity + return !options.can_distribute_opacity(); + }); + display_list->Dispatch(expector); + } +} + } // namespace testing } // namespace flutter diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index afce8d39130b2..682e8823c5607 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -8,6 +8,7 @@ #include "flutter/display_list/dl_blend_mode.h" #include "flutter/display_list/dl_op_flags.h" #include "flutter/display_list/dl_op_records.h" +#include "flutter/display_list/effects/dl_color_filters.h" #include "flutter/display_list/effects/dl_color_source.h" #include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/display_list/utils/dl_accumulation_rect.h" @@ -200,12 +201,6 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) { current_.setColorSource(source->shared()); is_ui_thread_safe_ = is_ui_thread_safe_ && source->isUIThreadSafe(); switch (source->type()) { - case DlColorSourceType::kColor: { - const DlColorColorSource* color_source = source->asColor(); - current_.setColorSource(nullptr); - setColor(color_source->color()); - break; - } case DlColorSourceType::kImage: { const DlImageColorSource* image_source = source->asImage(); FML_DCHECK(image_source); @@ -249,6 +244,7 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) { } } } + UpdateCurrentOpacityCompatibility(); } void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) { if (filter == nullptr) { @@ -294,6 +290,7 @@ void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) { } } } + UpdateCurrentOpacityCompatibility(); } void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) { if (filter == nullptr) { @@ -1952,11 +1949,9 @@ DlColor DisplayListBuilder::GetEffectiveColor(const DlPaint& paint, if (flags.applies_color()) { const DlColorSource* source = paint.getColorSourcePtr(); if (source) { - if (source->asColor()) { - color = source->asColor()->color(); - } else { - color = source->is_opaque() ? DlColor::kBlack() : kAnyColor; - } + // Suspecting that we need to modulate the ColorSource color by the + // color property, see https://github.com/flutter/flutter/issues/159507 + color = source->is_opaque() ? DlColor::kBlack() : kAnyColor; } else { color = paint.getColor(); } diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h index fb7464acc98a5..92dc9b83246c0 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -723,6 +723,7 @@ class DisplayListBuilder final : public virtual DlCanvas, current_opacity_compatibility_ = // current_.getColorFilter() == nullptr && // !current_.isInvertColors() && // + !current_.usesRuntimeEffect() && // IsOpacityCompatible(current_.getBlendMode()); } diff --git a/display_list/dl_paint.h b/display_list/dl_paint.h index ca5e69aa50811..409bd80602558 100644 --- a/display_list/dl_paint.h +++ b/display_list/dl_paint.h @@ -178,6 +178,11 @@ class DlPaint { bool isDefault() const { return *this == kDefault; } + bool usesRuntimeEffect() const { + return ((color_source_ && color_source_->asRuntimeEffect()) || + (image_filter_ && image_filter_->asRuntimeEffectFilter())); + } + bool operator==(DlPaint const& other) const; bool operator!=(DlPaint const& other) const { return !(*this == other); } diff --git a/display_list/dl_paint_unittests.cc b/display_list/dl_paint_unittests.cc index 9320c6486582a..1f76459af758a 100644 --- a/display_list/dl_paint_unittests.cc +++ b/display_list/dl_paint_unittests.cc @@ -4,6 +4,7 @@ #include "flutter/display_list/dl_paint.h" +#include "flutter/display_list/testing/dl_test_equality.h" #include "flutter/display_list/utils/dl_comparable.h" #include "gtest/gtest.h" @@ -55,11 +56,21 @@ TEST(DisplayListPaint, ConstructorDefaults) { EXPECT_NE(paint, DlPaint().setStrokeWidth(6)); EXPECT_NE(paint, DlPaint().setStrokeMiter(7)); - auto color_source = DlColorSource::MakeColor(DlColor::kMagenta()); + DlColor colors[2] = { + DlColor::kGreen(), + DlColor::kBlue(), + }; + float stops[2] = { + 0.0f, + 1.0f, + }; + auto color_source = DlColorSource::MakeLinear({0, 0}, {10, 10}, 2, colors, + stops, DlTileMode::kClamp); EXPECT_NE(paint, DlPaint().setColorSource(color_source)); - DlBlendColorFilter color_filter(DlColor::kYellow(), DlBlendMode::kDstIn); - EXPECT_NE(paint, DlPaint().setColorFilter(color_filter.shared())); + auto color_filter = + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kDstATop); + EXPECT_NE(paint, DlPaint().setColorFilter(color_filter)); auto image_filter = DlImageFilter::MakeBlur(1.3, 4.7, DlTileMode::kClamp); EXPECT_NE(paint, DlPaint().setImageFilter(image_filter)); @@ -93,22 +104,30 @@ TEST(DisplayListPaint, NullSharedPointerSetGet) { } TEST(DisplayListPaint, ChainingConstructor) { + DlColor colors[2] = { + DlColor::kGreen(), + DlColor::kBlue(), + }; + float stops[2] = { + 0.0f, + 1.0f, + }; DlPaint paint = - DlPaint() // - .setAntiAlias(true) // - .setInvertColors(true) // - .setColor(DlColor::kGreen()) // - .setAlpha(0x7F) // - .setBlendMode(DlBlendMode::kLuminosity) // - .setDrawStyle(DlDrawStyle::kStrokeAndFill) // - .setStrokeCap(DlStrokeCap::kSquare) // - .setStrokeJoin(DlStrokeJoin::kBevel) // - .setStrokeWidth(42) // - .setStrokeMiter(1.5) // - .setColorSource(DlColorSource::MakeColor(DlColor::kMagenta())) // + DlPaint() // + .setAntiAlias(true) // + .setInvertColors(true) // + .setColor(DlColor::kGreen()) // + .setAlpha(0x7F) // + .setBlendMode(DlBlendMode::kLuminosity) // + .setDrawStyle(DlDrawStyle::kStrokeAndFill) // + .setStrokeCap(DlStrokeCap::kSquare) // + .setStrokeJoin(DlStrokeJoin::kBevel) // + .setStrokeWidth(42) // + .setStrokeMiter(1.5) // + .setColorSource(DlColorSource::MakeLinear( // + {0, 0}, {10, 10}, 2, colors, stops, DlTileMode::kClamp)) // .setColorFilter( - DlBlendColorFilter(DlColor::kYellow(), DlBlendMode::kDstIn) - .shared()) + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kDstIn)) .setImageFilter(DlImageFilter::MakeBlur(1.3, 4.7, DlTileMode::kClamp)) .setMaskFilter(DlBlurMaskFilter(DlBlurStyle::kInner, 3.14).shared()); EXPECT_TRUE(paint.isAntiAlias()); @@ -122,9 +141,11 @@ TEST(DisplayListPaint, ChainingConstructor) { EXPECT_EQ(paint.getStrokeWidth(), 42); EXPECT_EQ(paint.getStrokeMiter(), 1.5); EXPECT_TRUE(Equals(paint.getColorSource(), - DlColorSource::MakeColor(DlColor::kMagenta()))); - EXPECT_EQ(*paint.getColorFilter(), - DlBlendColorFilter(DlColor::kYellow(), DlBlendMode::kDstIn)); + DlColorSource::MakeLinear({0, 0}, {10, 10}, 2, colors, + stops, DlTileMode::kClamp))); + EXPECT_TRUE(Equals( + paint.getColorFilter(), + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kDstIn))); EXPECT_TRUE(Equals(paint.getImageFilter(), DlImageFilter::MakeBlur(1.3, 4.7, DlTileMode::kClamp))); EXPECT_EQ(*paint.getMaskFilter(), @@ -133,5 +154,49 @@ TEST(DisplayListPaint, ChainingConstructor) { EXPECT_NE(paint, DlPaint()); } +TEST(DisplayListPaint, PaintDetectsRuntimeEffects) { + const auto runtime_effect = DlRuntimeEffect::MakeSkia( + SkRuntimeEffect::MakeForShader( + SkString("vec4 main(vec2 p) { return vec4(0); }")) + .effect); + auto color_source = DlColorSource::MakeRuntimeEffect( + runtime_effect, {}, std::make_shared>()); + auto image_filter = DlImageFilter::MakeRuntimeEffect( + runtime_effect, {}, std::make_shared>()); + DlPaint paint; + + EXPECT_FALSE(paint.usesRuntimeEffect()); + paint.setColorSource(color_source); + EXPECT_TRUE(paint.usesRuntimeEffect()); + paint.setColorSource(nullptr); + EXPECT_FALSE(paint.usesRuntimeEffect()); + + EXPECT_FALSE(paint.usesRuntimeEffect()); + paint.setImageFilter(image_filter); + EXPECT_TRUE(paint.usesRuntimeEffect()); + paint.setImageFilter(nullptr); + EXPECT_FALSE(paint.usesRuntimeEffect()); + + EXPECT_FALSE(paint.usesRuntimeEffect()); + paint.setColorSource(color_source); + EXPECT_TRUE(paint.usesRuntimeEffect()); + paint.setImageFilter(image_filter); + EXPECT_TRUE(paint.usesRuntimeEffect()); + paint.setImageFilter(nullptr); + EXPECT_TRUE(paint.usesRuntimeEffect()); + paint.setColorSource(nullptr); + EXPECT_FALSE(paint.usesRuntimeEffect()); + + EXPECT_FALSE(paint.usesRuntimeEffect()); + paint.setColorSource(color_source); + EXPECT_TRUE(paint.usesRuntimeEffect()); + paint.setImageFilter(image_filter); + EXPECT_TRUE(paint.usesRuntimeEffect()); + paint.setColorSource(nullptr); + EXPECT_TRUE(paint.usesRuntimeEffect()); + paint.setImageFilter(nullptr); + EXPECT_FALSE(paint.usesRuntimeEffect()); +} + } // namespace testing } // namespace flutter diff --git a/display_list/effects/color_filters/dl_blend_color_filter.cc b/display_list/effects/color_filters/dl_blend_color_filter.cc new file mode 100644 index 0000000000000..98f1af11c0a05 --- /dev/null +++ b/display_list/effects/color_filters/dl_blend_color_filter.cc @@ -0,0 +1,126 @@ +// 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/display_list/effects/color_filters/dl_blend_color_filter.h" + +namespace flutter { + +std::shared_ptr DlBlendColorFilter::Make( + DlColor color, + DlBlendMode mode) { + switch (mode) { + case DlBlendMode::kDst: { + return nullptr; + } + case DlBlendMode::kSrcOver: { + if (color.isTransparent()) { + return nullptr; + } + if (color.isOpaque()) { + mode = DlBlendMode::kSrc; + } + break; + } + case DlBlendMode::kDstOver: + case DlBlendMode::kDstOut: + case DlBlendMode::kSrcATop: + case DlBlendMode::kXor: + case DlBlendMode::kDarken: { + if (color.isTransparent()) { + return nullptr; + } + break; + } + case DlBlendMode::kDstIn: { + if (color.isOpaque()) { + return nullptr; + } + break; + } + default: + break; + } + return std::make_shared(color, mode); +} + +bool DlBlendColorFilter::modifies_transparent_black() const { + switch (mode_) { + // These modes all act like kSrc when the dest is all 0s. + // So they modify transparent black when the src color is + // not transparent. + case DlBlendMode::kSrc: + case DlBlendMode::kSrcOver: + case DlBlendMode::kDstOver: + case DlBlendMode::kSrcOut: + case DlBlendMode::kDstATop: + case DlBlendMode::kXor: + case DlBlendMode::kPlus: + case DlBlendMode::kScreen: + case DlBlendMode::kOverlay: + case DlBlendMode::kDarken: + case DlBlendMode::kLighten: + case DlBlendMode::kColorDodge: + case DlBlendMode::kColorBurn: + case DlBlendMode::kHardLight: + case DlBlendMode::kSoftLight: + case DlBlendMode::kDifference: + case DlBlendMode::kExclusion: + case DlBlendMode::kMultiply: + case DlBlendMode::kHue: + case DlBlendMode::kSaturation: + case DlBlendMode::kColor: + case DlBlendMode::kLuminosity: + return !color_.isTransparent(); + + // These modes are all like kDst when the dest is all 0s. + // So they never modify transparent black. + case DlBlendMode::kClear: + case DlBlendMode::kDst: + case DlBlendMode::kSrcIn: + case DlBlendMode::kDstIn: + case DlBlendMode::kDstOut: + case DlBlendMode::kSrcATop: + case DlBlendMode::kModulate: + return false; + } +} + +bool DlBlendColorFilter::can_commute_with_opacity() const { + switch (mode_) { + case DlBlendMode::kClear: + case DlBlendMode::kDst: + case DlBlendMode::kSrcIn: + case DlBlendMode::kDstIn: + case DlBlendMode::kDstOut: + case DlBlendMode::kSrcATop: + case DlBlendMode::kModulate: + return true; + + case DlBlendMode::kSrc: + case DlBlendMode::kSrcOver: + case DlBlendMode::kDstOver: + case DlBlendMode::kSrcOut: + case DlBlendMode::kDstATop: + case DlBlendMode::kXor: + case DlBlendMode::kPlus: + case DlBlendMode::kScreen: + case DlBlendMode::kOverlay: + case DlBlendMode::kDarken: + case DlBlendMode::kLighten: + case DlBlendMode::kColorDodge: + case DlBlendMode::kColorBurn: + case DlBlendMode::kHardLight: + case DlBlendMode::kSoftLight: + case DlBlendMode::kDifference: + case DlBlendMode::kExclusion: + case DlBlendMode::kMultiply: + case DlBlendMode::kHue: + case DlBlendMode::kSaturation: + case DlBlendMode::kColor: + case DlBlendMode::kLuminosity: + return color_.isTransparent(); + } +} + +} // namespace flutter diff --git a/display_list/effects/color_filters/dl_blend_color_filter.h b/display_list/effects/color_filters/dl_blend_color_filter.h new file mode 100644 index 0000000000000..f79f82ed1ac6c --- /dev/null +++ b/display_list/effects/color_filters/dl_blend_color_filter.h @@ -0,0 +1,60 @@ +// 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_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_BLEND_COLOR_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_BLEND_COLOR_FILTER_H_ + +#include "flutter/display_list/effects/dl_color_filter.h" + +namespace flutter { + +// The Blend type of ColorFilter which specifies modifying the +// colors as if the color specified in the Blend filter is the +// source color and the color drawn by the rendering operation +// is the destination color. The mode parameter of the Blend +// filter is then used to combine those colors. +class DlBlendColorFilter final : public DlColorFilter { + public: + DlBlendColorFilter(DlColor color, DlBlendMode mode) + : color_(color), mode_(mode) {} + DlBlendColorFilter(const DlBlendColorFilter& filter) + : DlBlendColorFilter(filter.color_, filter.mode_) {} + explicit DlBlendColorFilter(const DlBlendColorFilter* filter) + : DlBlendColorFilter(filter->color_, filter->mode_) {} + + DlColorFilterType type() const override { return DlColorFilterType::kBlend; } + size_t size() const override { return sizeof(*this); } + + bool modifies_transparent_black() const override; + bool can_commute_with_opacity() const override; + + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + const DlBlendColorFilter* asBlend() const override { return this; } + + DlColor color() const { return color_; } + DlBlendMode mode() const { return mode_; } + + protected: + bool equals_(DlColorFilter const& other) const override { + FML_DCHECK(other.type() == DlColorFilterType::kBlend); + auto that = static_cast(&other); + return color_ == that->color_ && mode_ == that->mode_; + } + + private: + static std::shared_ptr Make(DlColor color, + DlBlendMode mode); + + DlColor color_; + DlBlendMode mode_; + + friend class DlColorFilter; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_BLEND_COLOR_FILTER_H_ diff --git a/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.cc b/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.cc new file mode 100644 index 0000000000000..b2dc9e51dd820 --- /dev/null +++ b/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.cc @@ -0,0 +1,13 @@ +// 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/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h" + +namespace flutter { + +const std::shared_ptr + DlLinearToSrgbGammaColorFilter::kInstance = + std::make_shared(); + +} // namespace flutter diff --git a/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h b/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h new file mode 100644 index 0000000000000..b3c6ef1094e86 --- /dev/null +++ b/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h @@ -0,0 +1,46 @@ +// 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_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_LINEAR_TO_SRGB_GAMMA_COLOR_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_LINEAR_TO_SRGB_GAMMA_COLOR_FILTER_H_ + +#include "flutter/display_list/effects/dl_color_filter.h" + +namespace flutter { + +// The LinearToSrgb type of ColorFilter that applies the sRGB gamma curve +// to the rendered pixels. +class DlLinearToSrgbGammaColorFilter final : public DlColorFilter { + public: + DlLinearToSrgbGammaColorFilter() {} + DlLinearToSrgbGammaColorFilter(const DlLinearToSrgbGammaColorFilter& filter) + : DlLinearToSrgbGammaColorFilter() {} + explicit DlLinearToSrgbGammaColorFilter( + const DlLinearToSrgbGammaColorFilter* filter) + : DlLinearToSrgbGammaColorFilter() {} + + DlColorFilterType type() const override { + return DlColorFilterType::kLinearToSrgbGamma; + } + size_t size() const override { return sizeof(*this); } + bool modifies_transparent_black() const override { return false; } + bool can_commute_with_opacity() const override { return true; } + + std::shared_ptr shared() const override { return kInstance; } + + protected: + bool equals_(const DlColorFilter& other) const override { + FML_DCHECK(other.type() == DlColorFilterType::kLinearToSrgbGamma); + return true; + } + + private: + static const std::shared_ptr kInstance; + + friend class DlColorFilter; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_LINEAR_TO_SRGB_GAMMA_COLOR_FILTER_H_ diff --git a/display_list/effects/color_filters/dl_matrix_color_filter.cc b/display_list/effects/color_filters/dl_matrix_color_filter.cc new file mode 100644 index 0000000000000..8837c71bac941 --- /dev/null +++ b/display_list/effects/color_filters/dl_matrix_color_filter.cc @@ -0,0 +1,74 @@ +// 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/display_list/effects/color_filters/dl_matrix_color_filter.h" + +namespace flutter { + +std::shared_ptr DlMatrixColorFilter::Make( + const float matrix[20]) { + float product = 0; + for (int i = 0; i < 20; i++) { + product *= matrix[i]; + } + // If any of the elements of the matrix are infinity or NaN, then + // |product| will be NaN, otherwise 0. + if (product == 0) { + return std::make_shared(matrix); + } + return nullptr; +} + +bool DlMatrixColorFilter::modifies_transparent_black() const { + // Values are considered in non-premultiplied form when the matrix is + // applied, but we only care about this answer for whether it leaves + // an incoming color with a transparent alpha as transparent on output. + // Thus, we only need to consider the alpha part of the matrix equation, + // which is the last row. Since the incoming alpha value is 0, the last + // equation ends up becoming A' = matrix_[19]. Negative results will be + // clamped to the range [0,1] so we only care about positive values. + // Non-finite values are clamped to a zero alpha. + return (std::isfinite(matrix_[19]) && matrix_[19] > 0); +} + +bool DlMatrixColorFilter::can_commute_with_opacity() const { + // We need to check if: + // filter(color) * opacity == filter(color * opacity). + // + // filter(RGBA) = R' = [ R*m[ 0] + G*m[ 1] + B*m[ 2] + A*m[ 3] + m[ 4] ] + // G' = [ R*m[ 5] + G*m[ 6] + B*m[ 7] + A*m[ 8] + m[ 9] ] + // B' = [ R*m[10] + G*m[11] + B*m[12] + A*m[13] + m[14] ] + // A' = [ R*m[15] + G*m[16] + B*m[17] + A*m[18] + m[19] ] + // + // Applying the opacity only affects the alpha value since the operations + // are performed on non-premultiplied colors. (If the data is stored in + // premultiplied form, though, there may be rounding errors due to + // premul->unpremul->premul conversions.) + + // We test for the successful cases and return false if they fail so that + // we fail and return false if any matrix values are NaN. + + // If any of the alpha column are non-zero then the prior alpha affects + // the result color, so applying opacity before the filter will change + // the incoming alpha and therefore the colors that are produced. + if (!(matrix_[3] == 0 && // A does not affect R' + matrix_[8] == 0 && // A does not affect G' + matrix_[13] == 0)) { // A does not affect B' + return false; + } + + // Similarly, if any of the alpha row are non-zero then the prior colors + // affect the result alpha in a way that prevents opacity from commuting + // through the filter operation. + if (!(matrix_[15] == 0 && // R does not affect A' + matrix_[16] == 0 && // G does not affect A' + matrix_[17] == 0 && // B does not affect A' + matrix_[19] == 0)) { // A' is not offset by an absolute value + return false; + } + + return true; +} + +} // namespace flutter diff --git a/display_list/effects/color_filters/dl_matrix_color_filter.h b/display_list/effects/color_filters/dl_matrix_color_filter.h new file mode 100644 index 0000000000000..271fa8cac919c --- /dev/null +++ b/display_list/effects/color_filters/dl_matrix_color_filter.h @@ -0,0 +1,72 @@ +// 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_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_MATRIX_COLOR_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_MATRIX_COLOR_FILTER_H_ + +#include "flutter/display_list/effects/dl_color_filter.h" + +namespace flutter { + +// The Matrix type of ColorFilter which runs every pixel drawn by +// the rendering operation [iR,iG,iB,iA] through a vector/matrix +// multiplication, as in: +// +// [ oR ] [ m[ 0] m[ 1] m[ 2] m[ 3] m[ 4] ] [ iR ] +// [ oG ] [ m[ 5] m[ 6] m[ 7] m[ 8] m[ 9] ] [ iG ] +// [ oB ] = [ m[10] m[11] m[12] m[13] m[14] ] x [ iB ] +// [ oA ] [ m[15] m[16] m[17] m[18] m[19] ] [ iA ] +// [ 1 ] +// +// The resulting color [oR,oG,oB,oA] is then clamped to the range of +// valid pixel components before storing in the output. +// +// The incoming and outgoing [iR,iG,iB,iA] and [oR,oG,oB,oA] are +// considered to be non-premultiplied. When working on premultiplied +// pixel data, the necessary pre<->non-pre conversions must be performed. +class DlMatrixColorFilter final : public DlColorFilter { + public: + explicit DlMatrixColorFilter(const float matrix[20]) { + memcpy(matrix_, matrix, sizeof(matrix_)); + } + DlMatrixColorFilter(const DlMatrixColorFilter& filter) + : DlMatrixColorFilter(filter.matrix_) {} + explicit DlMatrixColorFilter(const DlMatrixColorFilter* filter) + : DlMatrixColorFilter(filter->matrix_) {} + + DlColorFilterType type() const override { return DlColorFilterType::kMatrix; } + size_t size() const override { return sizeof(*this); } + + bool modifies_transparent_black() const override; + bool can_commute_with_opacity() const override; + + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + const DlMatrixColorFilter* asMatrix() const override { return this; } + + const float& operator[](int index) const { return matrix_[index]; } + void get_matrix(float matrix[20]) const { + memcpy(matrix, matrix_, sizeof(matrix_)); + } + + protected: + bool equals_(const DlColorFilter& other) const override { + FML_DCHECK(other.type() == DlColorFilterType::kMatrix); + auto that = static_cast(&other); + return memcmp(matrix_, that->matrix_, sizeof(matrix_)) == 0; + } + + private: + static std::shared_ptr Make(const float matrix[20]); + + float matrix_[20]; + + friend class DlColorFilter; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_MATRIX_COLOR_FILTER_H_ diff --git a/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.cc b/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.cc new file mode 100644 index 0000000000000..30b3db2017360 --- /dev/null +++ b/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.cc @@ -0,0 +1,13 @@ +// 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/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h" + +namespace flutter { + +const std::shared_ptr + DlSrgbToLinearGammaColorFilter::kInstance = + std::make_shared(); + +} // namespace flutter diff --git a/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h b/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h new file mode 100644 index 0000000000000..393d8feee3f7f --- /dev/null +++ b/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h @@ -0,0 +1,46 @@ +// 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_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_SRGB_TO_LINEAR_GAMMA_COLOR_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_SRGB_TO_LINEAR_GAMMA_COLOR_FILTER_H_ + +#include "flutter/display_list/effects/dl_color_filter.h" + +namespace flutter { + +// The SrgbToLinear type of ColorFilter that applies the inverse of the sRGB +// gamma curve to the rendered pixels. +class DlSrgbToLinearGammaColorFilter final : public DlColorFilter { + public: + DlSrgbToLinearGammaColorFilter() {} + DlSrgbToLinearGammaColorFilter(const DlSrgbToLinearGammaColorFilter& filter) + : DlSrgbToLinearGammaColorFilter() {} + explicit DlSrgbToLinearGammaColorFilter( + const DlSrgbToLinearGammaColorFilter* filter) + : DlSrgbToLinearGammaColorFilter() {} + + DlColorFilterType type() const override { + return DlColorFilterType::kSrgbToLinearGamma; + } + size_t size() const override { return sizeof(*this); } + bool modifies_transparent_black() const override { return false; } + bool can_commute_with_opacity() const override { return true; } + + std::shared_ptr shared() const override { return kInstance; } + + protected: + bool equals_(const DlColorFilter& other) const override { + FML_DCHECK(other.type() == DlColorFilterType::kSrgbToLinearGamma); + return true; + } + + private: + static const std::shared_ptr kInstance; + + friend class DlColorFilter; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_FILTERS_DL_SRGB_TO_LINEAR_GAMMA_COLOR_FILTER_H_ diff --git a/display_list/effects/color_sources/dl_color_color_source.cc b/display_list/effects/color_sources/dl_color_color_source.cc deleted file mode 100644 index e9f56f758c24f..0000000000000 --- a/display_list/effects/color_sources/dl_color_color_source.cc +++ /dev/null @@ -1,15 +0,0 @@ -// 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/display_list/effects/color_sources/dl_color_color_source.h" - -namespace flutter { - -bool DlColorColorSource::equals_(DlColorSource const& other) const { - FML_DCHECK(other.type() == DlColorSourceType::kColor); - auto that = static_cast(&other); - return color_ == that->color_; -} - -} // namespace flutter diff --git a/display_list/effects/color_sources/dl_color_color_source.h b/display_list/effects/color_sources/dl_color_color_source.h deleted file mode 100644 index c873448ae44cf..0000000000000 --- a/display_list/effects/color_sources/dl_color_color_source.h +++ /dev/null @@ -1,42 +0,0 @@ -// 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_DISPLAY_LIST_EFFECTS_COLOR_SOURCES_DL_COLOR_COLOR_SOURCE_H_ -#define FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_SOURCES_DL_COLOR_COLOR_SOURCE_H_ - -#include "flutter/display_list/effects/dl_color_source.h" - -namespace flutter { - -class DlColorColorSource final : public DlColorSource { - public: - explicit DlColorColorSource(DlColor color) : color_(color) {} - - bool isUIThreadSafe() const override { return true; } - - std::shared_ptr shared() const override { - return std::make_shared(color_); - } - - const DlColorColorSource* asColor() const override { return this; } - - DlColorSourceType type() const override { return DlColorSourceType::kColor; } - size_t size() const override { return sizeof(*this); } - - bool is_opaque() const override { return color_.getAlpha() == 255; } - - DlColor color() const { return color_; } - - protected: - bool equals_(DlColorSource const& other) const override; - - private: - DlColor color_; - - FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlColorColorSource); -}; - -} // namespace flutter - -#endif // FLUTTER_DISPLAY_LIST_EFFECTS_COLOR_SOURCES_DL_COLOR_COLOR_SOURCE_H_ diff --git a/display_list/effects/dl_color_filter.cc b/display_list/effects/dl_color_filter.cc index 2ad15e0ab92bf..c78cfa3ca2398 100644 --- a/display_list/effects/dl_color_filter.cc +++ b/display_list/effects/dl_color_filter.cc @@ -5,196 +5,34 @@ #include "flutter/display_list/effects/dl_color_filter.h" #include "flutter/display_list/dl_color.h" +#include "flutter/display_list/effects/color_filters/dl_blend_color_filter.h" +#include "flutter/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h" +#include "flutter/display_list/effects/color_filters/dl_matrix_color_filter.h" +#include "flutter/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h" namespace flutter { -std::shared_ptr DlBlendColorFilter::Make(DlColor color, - DlBlendMode mode) { - switch (mode) { - case DlBlendMode::kDst: { - return nullptr; - } - case DlBlendMode::kSrcOver: { - if (color.isTransparent()) { - return nullptr; - } - if (color.isOpaque()) { - mode = DlBlendMode::kSrc; - } - break; - } - case DlBlendMode::kDstOver: - case DlBlendMode::kDstOut: - case DlBlendMode::kSrcATop: - case DlBlendMode::kXor: - case DlBlendMode::kDarken: { - if (color.isTransparent()) { - return nullptr; - } - break; - } - case DlBlendMode::kDstIn: { - if (color.isOpaque()) { - return nullptr; - } - break; - } - default: - break; - } - return std::make_shared(color, mode); +std::shared_ptr DlColorFilter::MakeBlend( + DlColor color, + DlBlendMode mode) { + // Delegate to a method private to DlBlendColorFilter due to private + // constructor preventing |make_shared| from here. + return DlBlendColorFilter::Make(color, mode); } -bool DlBlendColorFilter::modifies_transparent_black() const { - switch (mode_) { - // These modes all act like kSrc when the dest is all 0s. - // So they modify transparent black when the src color is - // not transparent. - case DlBlendMode::kSrc: - case DlBlendMode::kSrcOver: - case DlBlendMode::kDstOver: - case DlBlendMode::kSrcOut: - case DlBlendMode::kDstATop: - case DlBlendMode::kXor: - case DlBlendMode::kPlus: - case DlBlendMode::kScreen: - case DlBlendMode::kOverlay: - case DlBlendMode::kDarken: - case DlBlendMode::kLighten: - case DlBlendMode::kColorDodge: - case DlBlendMode::kColorBurn: - case DlBlendMode::kHardLight: - case DlBlendMode::kSoftLight: - case DlBlendMode::kDifference: - case DlBlendMode::kExclusion: - case DlBlendMode::kMultiply: - case DlBlendMode::kHue: - case DlBlendMode::kSaturation: - case DlBlendMode::kColor: - case DlBlendMode::kLuminosity: - return !color_.isTransparent(); - - // These modes are all like kDst when the dest is all 0s. - // So they never modify transparent black. - case DlBlendMode::kClear: - case DlBlendMode::kDst: - case DlBlendMode::kSrcIn: - case DlBlendMode::kDstIn: - case DlBlendMode::kDstOut: - case DlBlendMode::kSrcATop: - case DlBlendMode::kModulate: - return false; - } -} - -bool DlBlendColorFilter::can_commute_with_opacity() const { - switch (mode_) { - case DlBlendMode::kClear: - case DlBlendMode::kDst: - case DlBlendMode::kSrcIn: - case DlBlendMode::kDstIn: - case DlBlendMode::kDstOut: - case DlBlendMode::kSrcATop: - case DlBlendMode::kModulate: - return true; - - case DlBlendMode::kSrc: - case DlBlendMode::kSrcOver: - case DlBlendMode::kDstOver: - case DlBlendMode::kSrcOut: - case DlBlendMode::kDstATop: - case DlBlendMode::kXor: - case DlBlendMode::kPlus: - case DlBlendMode::kScreen: - case DlBlendMode::kOverlay: - case DlBlendMode::kDarken: - case DlBlendMode::kLighten: - case DlBlendMode::kColorDodge: - case DlBlendMode::kColorBurn: - case DlBlendMode::kHardLight: - case DlBlendMode::kSoftLight: - case DlBlendMode::kDifference: - case DlBlendMode::kExclusion: - case DlBlendMode::kMultiply: - case DlBlendMode::kHue: - case DlBlendMode::kSaturation: - case DlBlendMode::kColor: - case DlBlendMode::kLuminosity: - return color_.isTransparent(); - } -} - -std::shared_ptr DlMatrixColorFilter::Make( +std::shared_ptr DlColorFilter::MakeMatrix( const float matrix[20]) { - float product = 0; - for (int i = 0; i < 20; i++) { - product *= matrix[i]; - } - // If any of the elements of the matrix are infinity or NaN, then - // |product| will be NaN, otherwise 0. - if (product == 0) { - return std::make_shared(matrix); - } - return nullptr; + // Delegate to a method private to DlBlendColorFilter due to private + // constructor preventing |make_shared| from here. + return DlMatrixColorFilter::Make(matrix); } -bool DlMatrixColorFilter::modifies_transparent_black() const { - // Values are considered in non-premultiplied form when the matrix is - // applied, but we only care about this answer for whether it leaves - // an incoming color with a transparent alpha as transparent on output. - // Thus, we only need to consider the alpha part of the matrix equation, - // which is the last row. Since the incoming alpha value is 0, the last - // equation ends up becoming A' = matrix_[19]. Negative results will be - // clamped to the range [0,1] so we only care about positive values. - // Non-finite values are clamped to a zero alpha. - return (std::isfinite(matrix_[19]) && matrix_[19] > 0); +std::shared_ptr DlColorFilter::MakeSrgbToLinearGamma() { + return DlSrgbToLinearGammaColorFilter::kInstance; } -bool DlMatrixColorFilter::can_commute_with_opacity() const { - // We need to check if: - // filter(color) * opacity == filter(color * opacity). - // - // filter(RGBA) = R' = [ R*m[ 0] + G*m[ 1] + B*m[ 2] + A*m[ 3] + m[ 4] ] - // G' = [ R*m[ 5] + G*m[ 6] + B*m[ 7] + A*m[ 8] + m[ 9] ] - // B' = [ R*m[10] + G*m[11] + B*m[12] + A*m[13] + m[14] ] - // A' = [ R*m[15] + G*m[16] + B*m[17] + A*m[18] + m[19] ] - // - // Applying the opacity only affects the alpha value since the operations - // are performed on non-premultiplied colors. (If the data is stored in - // premultiplied form, though, there may be rounding errors due to - // premul->unpremul->premul conversions.) - - // We test for the successful cases and return false if they fail so that - // we fail and return false if any matrix values are NaN. - - // If any of the alpha column are non-zero then the prior alpha affects - // the result color, so applying opacity before the filter will change - // the incoming alpha and therefore the colors that are produced. - if (!(matrix_[3] == 0 && // A does not affect R' - matrix_[8] == 0 && // A does not affect G' - matrix_[13] == 0)) { // A does not affect B' - return false; - } - - // Similarly, if any of the alpha row are non-zero then the prior colors - // affect the result alpha in a way that prevents opacity from commuting - // through the filter operation. - if (!(matrix_[15] == 0 && // R does not affect A' - matrix_[16] == 0 && // G does not affect A' - matrix_[17] == 0 && // B does not affect A' - matrix_[19] == 0)) { // A' is not offset by an absolute value - return false; - } - - return true; +std::shared_ptr DlColorFilter::MakeLinearToSrgbGamma() { + return DlLinearToSrgbGammaColorFilter::kInstance; } -const std::shared_ptr - DlSrgbToLinearGammaColorFilter::kInstance = - std::make_shared(); - -const std::shared_ptr - DlLinearToSrgbGammaColorFilter::kInstance = - std::make_shared(); - } // namespace flutter diff --git a/display_list/effects/dl_color_filter.h b/display_list/effects/dl_color_filter.h index 42a4845e0a90c..c3c0d64241edb 100644 --- a/display_list/effects/dl_color_filter.h +++ b/display_list/effects/dl_color_filter.h @@ -15,10 +15,6 @@ namespace flutter { class DlBlendColorFilter; class DlMatrixColorFilter; -// The DisplayList ColorFilter class. This class implements all of the -// facilities and adheres to the design goals of the |DlAttribute| base -// class. - // An enumerated type for the supported ColorFilter operations. enum class DlColorFilterType { kBlend, @@ -27,8 +23,51 @@ enum class DlColorFilterType { kLinearToSrgbGamma, }; +/// The DisplayList ColorFilter base class. This class implements all of the +/// facilities and adheres to the design goals of the |DlAttribute| base +/// class. class DlColorFilter : public DlAttribute { public: + /// Return a shared pointer to a DlColorFilter that acts as if blending + /// the specified color over the rendered colors using the specified + /// blend mode, or a nullptr if the operation would be a NOP. + /// + /// The blend mode takes the color from the filter as the source color and + /// the rendered color as the destination color. + static std::shared_ptr MakeBlend(DlColor color, + DlBlendMode mode); + + /// Return a shared pointer to a DlColorFilter which transforms each + /// rendered color using a per-component equation specified by the + /// contents of the specified 5 column by 4 row matrix specified in + /// row major order, or a null pointer if the operation would be a NOP. + /// + /// The filter runs every pixel drawn by the rendering operation + /// [iR,iG,iB,iA] through a vector/matrix multiplication, as in: + /// + /// [ oR ] [ m[ 0] m[ 1] m[ 2] m[ 3] m[ 4] ] [ iR ] + /// [ oG ] [ m[ 5] m[ 6] m[ 7] m[ 8] m[ 9] ] [ iG ] + /// [ oB ] = [ m[10] m[11] m[12] m[13] m[14] ] x [ iB ] + /// [ oA ] [ m[15] m[16] m[17] m[18] m[19] ] [ iA ] + /// [ 1 ] + /// + /// The resulting color [oR,oG,oB,oA] is then clamped to the range of + /// valid pixel components before storing in the output. + /// + /// The incoming and outgoing [iR,iG,iB,iA] and [oR,oG,oB,oA] are + /// considered to be non-premultiplied. When working on premultiplied + /// pixel data, the necessary pre<->non-pre conversions must be performed. + static std::shared_ptr MakeMatrix( + const float matrix[20]); + + /// Return a shared pointer to a singleton DlColorFilter that transforms + /// each rendered pixel from Srgb to Linear gamma space. + static std::shared_ptr MakeSrgbToLinearGamma(); + + /// Return a shared pointer to a singleton DlColorFilter that transforms + /// each rendered pixel from Linear to Srgb gamma space. + static std::shared_ptr MakeLinearToSrgbGamma(); + // Return a boolean indicating whether the color filtering operation will // modify transparent black. This is typically used to determine if applying // the ColorFilter to a temporary saveLayer buffer will turn the surrounding @@ -48,173 +87,10 @@ class DlColorFilter : public DlAttribute { // type of ColorFilter, otherwise return nullptr. virtual const DlMatrixColorFilter* asMatrix() const { return nullptr; } - // asSrgb<->Linear is not needed because it has no properties to query. + // asSrgb<->Linear are not needed because it has no properties to query. // Its type fully specifies its operation. }; -// The Blend type of ColorFilter which specifies modifying the -// colors as if the color specified in the Blend filter is the -// source color and the color drawn by the rendering operation -// is the destination color. The mode parameter of the Blend -// filter is then used to combine those colors. -class DlBlendColorFilter final : public DlColorFilter { - public: - DlBlendColorFilter(DlColor color, DlBlendMode mode) - : color_(color), mode_(mode) {} - DlBlendColorFilter(const DlBlendColorFilter& filter) - : DlBlendColorFilter(filter.color_, filter.mode_) {} - explicit DlBlendColorFilter(const DlBlendColorFilter* filter) - : DlBlendColorFilter(filter->color_, filter->mode_) {} - - static std::shared_ptr Make(DlColor color, DlBlendMode mode); - - DlColorFilterType type() const override { return DlColorFilterType::kBlend; } - size_t size() const override { return sizeof(*this); } - - bool modifies_transparent_black() const override; - bool can_commute_with_opacity() const override; - - std::shared_ptr shared() const override { - return std::make_shared(this); - } - - const DlBlendColorFilter* asBlend() const override { return this; } - - DlColor color() const { return color_; } - DlBlendMode mode() const { return mode_; } - - protected: - bool equals_(DlColorFilter const& other) const override { - FML_DCHECK(other.type() == DlColorFilterType::kBlend); - auto that = static_cast(&other); - return color_ == that->color_ && mode_ == that->mode_; - } - - private: - DlColor color_; - DlBlendMode mode_; -}; - -// The Matrix type of ColorFilter which runs every pixel drawn by -// the rendering operation [iR,iG,iB,iA] through a vector/matrix -// multiplication, as in: -// -// [ oR ] [ m[ 0] m[ 1] m[ 2] m[ 3] m[ 4] ] [ iR ] -// [ oG ] [ m[ 5] m[ 6] m[ 7] m[ 8] m[ 9] ] [ iG ] -// [ oB ] = [ m[10] m[11] m[12] m[13] m[14] ] x [ iB ] -// [ oA ] [ m[15] m[16] m[17] m[18] m[19] ] [ iA ] -// [ 1 ] -// -// The resulting color [oR,oG,oB,oA] is then clamped to the range of -// valid pixel components before storing in the output. -// -// The incoming and outgoing [iR,iG,iB,iA] and [oR,oG,oB,oA] are -// considered to be non-premultiplied. When working on premultiplied -// pixel data, the necessary pre<->non-pre conversions must be performed. -class DlMatrixColorFilter final : public DlColorFilter { - public: - explicit DlMatrixColorFilter(const float matrix[20]) { - memcpy(matrix_, matrix, sizeof(matrix_)); - } - DlMatrixColorFilter(const DlMatrixColorFilter& filter) - : DlMatrixColorFilter(filter.matrix_) {} - explicit DlMatrixColorFilter(const DlMatrixColorFilter* filter) - : DlMatrixColorFilter(filter->matrix_) {} - - static std::shared_ptr Make(const float matrix[20]); - - DlColorFilterType type() const override { return DlColorFilterType::kMatrix; } - size_t size() const override { return sizeof(*this); } - - bool modifies_transparent_black() const override; - bool can_commute_with_opacity() const override; - - std::shared_ptr shared() const override { - return std::make_shared(this); - } - - const DlMatrixColorFilter* asMatrix() const override { return this; } - - const float& operator[](int index) const { return matrix_[index]; } - void get_matrix(float matrix[20]) const { - memcpy(matrix, matrix_, sizeof(matrix_)); - } - - protected: - bool equals_(const DlColorFilter& other) const override { - FML_DCHECK(other.type() == DlColorFilterType::kMatrix); - auto that = static_cast(&other); - return memcmp(matrix_, that->matrix_, sizeof(matrix_)) == 0; - } - - private: - float matrix_[20]; -}; - -// The SrgbToLinear type of ColorFilter that applies the inverse of the sRGB -// gamma curve to the rendered pixels. -class DlSrgbToLinearGammaColorFilter final : public DlColorFilter { - public: - static const std::shared_ptr kInstance; - - DlSrgbToLinearGammaColorFilter() {} - DlSrgbToLinearGammaColorFilter(const DlSrgbToLinearGammaColorFilter& filter) - : DlSrgbToLinearGammaColorFilter() {} - explicit DlSrgbToLinearGammaColorFilter( - const DlSrgbToLinearGammaColorFilter* filter) - : DlSrgbToLinearGammaColorFilter() {} - - DlColorFilterType type() const override { - return DlColorFilterType::kSrgbToLinearGamma; - } - size_t size() const override { return sizeof(*this); } - bool modifies_transparent_black() const override { return false; } - bool can_commute_with_opacity() const override { return true; } - - std::shared_ptr shared() const override { return kInstance; } - - protected: - bool equals_(const DlColorFilter& other) const override { - FML_DCHECK(other.type() == DlColorFilterType::kSrgbToLinearGamma); - return true; - } - - private: - friend class DlColorFilter; -}; - -// The LinearToSrgb type of ColorFilter that applies the sRGB gamma curve -// to the rendered pixels. -class DlLinearToSrgbGammaColorFilter final : public DlColorFilter { - public: - static const std::shared_ptr kInstance; - - DlLinearToSrgbGammaColorFilter() {} - DlLinearToSrgbGammaColorFilter(const DlLinearToSrgbGammaColorFilter& filter) - : DlLinearToSrgbGammaColorFilter() {} - explicit DlLinearToSrgbGammaColorFilter( - const DlLinearToSrgbGammaColorFilter* filter) - : DlLinearToSrgbGammaColorFilter() {} - - DlColorFilterType type() const override { - return DlColorFilterType::kLinearToSrgbGamma; - } - size_t size() const override { return sizeof(*this); } - bool modifies_transparent_black() const override { return false; } - bool can_commute_with_opacity() const override { return true; } - - std::shared_ptr shared() const override { return kInstance; } - - protected: - bool equals_(const DlColorFilter& other) const override { - FML_DCHECK(other.type() == DlColorFilterType::kLinearToSrgbGamma); - return true; - } - - private: - friend class DlColorFilter; -}; - } // namespace flutter #endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_COLOR_FILTER_H_ diff --git a/display_list/effects/dl_color_filter_unittests.cc b/display_list/effects/dl_color_filter_unittests.cc index 157348f3cf3ae..524b8fb481cc4 100644 --- a/display_list/effects/dl_color_filter_unittests.cc +++ b/display_list/effects/dl_color_filter_unittests.cc @@ -3,6 +3,8 @@ // found in the LICENSE file. #include "flutter/display_list/effects/dl_color_filter.h" + +#include "flutter/display_list/effects/dl_color_filters.h" #include "flutter/display_list/testing/dl_test_equality.h" namespace flutter { @@ -135,7 +137,7 @@ TEST(DisplayListColorFilter, SrgbToLinearEquals) { DlSrgbToLinearGammaColorFilter filter1; DlSrgbToLinearGammaColorFilter filter2; TestEquals(filter1, filter2); - TestEquals(filter1, *DlSrgbToLinearGammaColorFilter::kInstance); + TestEquals(filter1, *DlColorFilter::MakeSrgbToLinearGamma()); } TEST(DisplayListColorFilter, LinearToSrgbConstructor) { @@ -152,7 +154,7 @@ TEST(DisplayListColorFilter, LinearToSrgbEquals) { DlLinearToSrgbGammaColorFilter filter1; DlLinearToSrgbGammaColorFilter filter2; TestEquals(filter1, filter2); - TestEquals(filter1, *DlLinearToSrgbGammaColorFilter::kInstance); + TestEquals(filter1, *DlColorFilter::MakeLinearToSrgbGamma()); } } // namespace testing diff --git a/display_list/effects/dl_color_filters.h b/display_list/effects/dl_color_filters.h new file mode 100644 index 0000000000000..48bb78ae67bd2 --- /dev/null +++ b/display_list/effects/dl_color_filters.h @@ -0,0 +1,13 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_COLOR_FILTERS_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_COLOR_FILTERS_H_ + +#include "flutter/display_list/effects/color_filters/dl_blend_color_filter.h" +#include "flutter/display_list/effects/color_filters/dl_linear_to_srgb_gamma_color_filter.h" +#include "flutter/display_list/effects/color_filters/dl_matrix_color_filter.h" +#include "flutter/display_list/effects/color_filters/dl_srgb_to_linear_gamma_color_filter.h" + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_COLOR_FILTERS_H_ diff --git a/display_list/effects/dl_color_source.cc b/display_list/effects/dl_color_source.cc index 6009096b3dab3..5a5fa8b1fbf19 100644 --- a/display_list/effects/dl_color_source.cc +++ b/display_list/effects/dl_color_source.cc @@ -20,10 +20,6 @@ static void DlGradientDeleter(void* p) { ::operator delete(p); } -std::shared_ptr DlColorSource::MakeColor(DlColor color) { - return std::make_shared(color); -} - std::shared_ptr DlColorSource::MakeImage( const sk_sp& image, DlTileMode horizontal_tile_mode, diff --git a/display_list/effects/dl_color_source.h b/display_list/effects/dl_color_source.h index 8b25644248306..05fe3ca5853d2 100644 --- a/display_list/effects/dl_color_source.h +++ b/display_list/effects/dl_color_source.h @@ -15,7 +15,6 @@ namespace flutter { -class DlColorColorSource; class DlImageColorSource; class DlLinearGradientColorSource; class DlRadialGradientColorSource; @@ -34,7 +33,6 @@ class DlRuntimeEffectColorSource; // attributes, and the final blend with the pixels in the destination. enum class DlColorSourceType { - kColor, kImage, kLinearGradient, kRadialGradient, @@ -45,8 +43,6 @@ enum class DlColorSourceType { class DlColorSource : public DlAttribute { public: - static std::shared_ptr MakeColor(DlColor color); - static std::shared_ptr MakeImage( const sk_sp& image, DlTileMode horizontal_tile_mode, @@ -120,10 +116,6 @@ class DlColorSource : public DlAttribute { /// virtual bool isGradient() const { return false; } - // Return a DlColorColorSource pointer to this object iff it is an Color - // type of ColorSource, otherwise return nullptr. - virtual const DlColorColorSource* asColor() const { return nullptr; } - // Return a DlImageColorSource pointer to this object iff it is an Image // type of ColorSource, otherwise return nullptr. virtual const DlImageColorSource* asImage() const { return nullptr; } diff --git a/display_list/effects/dl_color_source_unittests.cc b/display_list/effects/dl_color_source_unittests.cc index 423c5c405bbb5..944de9c994836 100644 --- a/display_list/effects/dl_color_source_unittests.cc +++ b/display_list/effects/dl_color_source_unittests.cc @@ -88,53 +88,6 @@ static constexpr DlPoint kTestPoints2[2] = { DlPoint(107, 118), }; -TEST(DisplayListColorSource, ColorConstructor) { - DlColorColorSource source(DlColor::kRed()); -} - -TEST(DisplayListColorSource, ColorShared) { - DlColorColorSource source(DlColor::kRed()); - ASSERT_NE(source.shared().get(), &source); - ASSERT_EQ(*source.shared(), source); -} - -TEST(DisplayListColorSource, ColorAsColor) { - DlColorColorSource source(DlColor::kRed()); - ASSERT_NE(source.asColor(), nullptr); - ASSERT_EQ(source.asColor(), &source); - - ASSERT_EQ(source.asImage(), nullptr); - ASSERT_EQ(source.asLinearGradient(), nullptr); - ASSERT_EQ(source.asRadialGradient(), nullptr); - ASSERT_EQ(source.asConicalGradient(), nullptr); - ASSERT_EQ(source.asSweepGradient(), nullptr); - ASSERT_EQ(source.asRuntimeEffect(), nullptr); -} - -TEST(DisplayListColorSource, ColorContents) { - DlColorColorSource source(DlColor::kRed()); - ASSERT_EQ(source.color(), DlColor::kRed()); - ASSERT_EQ(source.is_opaque(), true); - for (int i = 0; i < 255; i++) { - SkColor alpha_color = SkColorSetA(SK_ColorRED, i); - auto const alpha_source = DlColorColorSource(DlColor(alpha_color)); - ASSERT_EQ(alpha_source.color(), alpha_color); - ASSERT_EQ(alpha_source.is_opaque(), false); - } -} - -TEST(DisplayListColorSource, ColorEquals) { - DlColorColorSource source1(DlColor::kRed()); - DlColorColorSource source2(DlColor::kRed()); - TestEquals(source1, source2); -} - -TEST(DisplayListColorSource, ColorNotEquals) { - DlColorColorSource source1(DlColor::kRed()); - DlColorColorSource source2(DlColor::kBlue()); - TestNotEquals(source1, source2, "Color differs"); -} - TEST(DisplayListColorSource, ImageConstructor) { DlImageColorSource source(kTestImage1, DlTileMode::kClamp, DlTileMode::kClamp, DlImageSampling::kLinear, &kTestMatrix1); @@ -153,11 +106,11 @@ TEST(DisplayListColorSource, ImageAsImage) { ASSERT_NE(source.asImage(), nullptr); ASSERT_EQ(source.asImage(), &source); - ASSERT_EQ(source.asColor(), nullptr); ASSERT_EQ(source.asLinearGradient(), nullptr); ASSERT_EQ(source.asRadialGradient(), nullptr); ASSERT_EQ(source.asConicalGradient(), nullptr); ASSERT_EQ(source.asSweepGradient(), nullptr); + ASSERT_EQ(source.asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, ImageContents) { @@ -251,7 +204,6 @@ TEST(DisplayListColorSource, LinearGradientAsLinear) { ASSERT_NE(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asLinearGradient(), source.get()); - ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); @@ -370,7 +322,6 @@ TEST(DisplayListColorSource, RadialGradientAsRadial) { ASSERT_NE(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), source.get()); - ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); @@ -489,7 +440,6 @@ TEST(DisplayListColorSource, ConicalGradientAsConical) { ASSERT_NE(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), source.get()); - ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); @@ -624,7 +574,6 @@ TEST(DisplayListColorSource, SweepGradientAsSweep) { ASSERT_NE(source->asSweepGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), source.get()); - ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); @@ -743,7 +692,6 @@ TEST(DisplayListColorSource, RuntimeEffect) { ASSERT_NE(source2->asRuntimeEffect(), source1.get()); ASSERT_EQ(source1->asImage(), nullptr); - ASSERT_EQ(source1->asColor(), nullptr); ASSERT_EQ(source1->asLinearGradient(), nullptr); ASSERT_EQ(source1->asRadialGradient(), nullptr); ASSERT_EQ(source1->asConicalGradient(), nullptr); diff --git a/display_list/effects/dl_color_sources.h b/display_list/effects/dl_color_sources.h index ce5d802d04176..23e810adc4eb7 100644 --- a/display_list/effects/dl_color_sources.h +++ b/display_list/effects/dl_color_sources.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_DISPLAY_LIST_EFFECTS_DL_COLOR_SOURCES_H_ #define FLUTTER_DISPLAY_LIST_EFFECTS_DL_COLOR_SOURCES_H_ -#include "flutter/display_list/effects/color_sources/dl_color_color_source.h" #include "flutter/display_list/effects/color_sources/dl_conical_gradient_color_source.h" #include "flutter/display_list/effects/color_sources/dl_image_color_source.h" #include "flutter/display_list/effects/color_sources/dl_linear_gradient_color_source.h" diff --git a/display_list/effects/dl_image_filter_unittests.cc b/display_list/effects/dl_image_filter_unittests.cc index b9996f34f355a..150e85c078e8e 100644 --- a/display_list/effects/dl_image_filter_unittests.cc +++ b/display_list/effects/dl_image_filter_unittests.cc @@ -7,7 +7,7 @@ #include "flutter/display_list/dl_color.h" #include "flutter/display_list/dl_sampling_options.h" #include "flutter/display_list/dl_tile_mode.h" -#include "flutter/display_list/effects/dl_color_filter.h" +#include "flutter/display_list/effects/dl_color_filters.h" #include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/display_list/testing/dl_test_equality.h" #include "flutter/display_list/utils/dl_comparable.h" diff --git a/display_list/skia/dl_sk_conversions.cc b/display_list/skia/dl_sk_conversions.cc index b97b7d584a32b..16b3455f9dc0b 100644 --- a/display_list/skia/dl_sk_conversions.cc +++ b/display_list/skia/dl_sk_conversions.cc @@ -4,6 +4,7 @@ #include "flutter/display_list/skia/dl_sk_conversions.h" +#include "flutter/display_list/effects/dl_color_filters.h" #include "flutter/display_list/effects/dl_color_sources.h" #include "flutter/display_list/effects/dl_image_filters.h" #include "third_party/skia/include/core/SkColorFilter.h" @@ -82,11 +83,6 @@ sk_sp ToSk(const DlColorSource* source) { return sk_colors; }; switch (source->type()) { - case DlColorSourceType::kColor: { - const DlColorColorSource* color_source = source->asColor(); - FML_DCHECK(color_source != nullptr); - return SkShaders::Color(ToSk(color_source->color())); - } case DlColorSourceType::kImage: { const DlImageColorSource* image_source = source->asImage(); FML_DCHECK(image_source != nullptr); diff --git a/display_list/skia/dl_sk_conversions_unittests.cc b/display_list/skia/dl_sk_conversions_unittests.cc index 7d3ad72b54797..81606246e76c4 100644 --- a/display_list/skia/dl_sk_conversions_unittests.cc +++ b/display_list/skia/dl_sk_conversions_unittests.cc @@ -7,6 +7,7 @@ #include "flutter/display_list/dl_sampling_options.h" #include "flutter/display_list/dl_tile_mode.h" #include "flutter/display_list/dl_vertices.h" +#include "flutter/display_list/effects/dl_color_filters.h" #include "flutter/display_list/effects/dl_color_sources.h" #include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/display_list/skia/dl_sk_conversions.h" @@ -158,7 +159,7 @@ TEST(DisplayListSkConversions, BlendColorFilterModifiesTransparency) { DlBlendColorFilter filter(color, mode); auto srgb = SkColorSpace::MakeSRGB(); if (filter.modifies_transparent_black()) { - auto dl_filter = DlBlendColorFilter::Make(color, mode); + auto dl_filter = DlColorFilter::MakeBlend(color, mode); auto sk_filter = ToSk(filter); ASSERT_NE(dl_filter, nullptr) << desc; ASSERT_NE(sk_filter, nullptr) << desc; @@ -167,7 +168,7 @@ TEST(DisplayListSkConversions, BlendColorFilterModifiesTransparency) { SkColors::kTransparent) << desc; } else { - auto dl_filter = DlBlendColorFilter::Make(color, mode); + auto dl_filter = DlColorFilter::MakeBlend(color, mode); auto sk_filter = ToSk(filter); EXPECT_EQ(dl_filter == nullptr, sk_filter == nullptr) << desc; ASSERT_TRUE(sk_filter == nullptr || @@ -267,7 +268,7 @@ TEST(DisplayListSkConversions, MatrixColorFilterModifiesTransparency) { "matrix[" + std::to_string(element) + "] = " + std::to_string(value); matrix[element] = value; DlMatrixColorFilter filter(matrix); - auto dl_filter = DlMatrixColorFilter::Make(matrix); + auto dl_filter = DlColorFilter::MakeMatrix(matrix); auto sk_filter = ToSk(filter); auto srgb = SkColorSpace::MakeSRGB(); EXPECT_EQ(dl_filter == nullptr, sk_filter == nullptr); diff --git a/display_list/skia/dl_sk_paint_dispatcher_unittests.cc b/display_list/skia/dl_sk_paint_dispatcher_unittests.cc index e515537ba203e..f0bd925c1c5b2 100644 --- a/display_list/skia/dl_sk_paint_dispatcher_unittests.cc +++ b/display_list/skia/dl_sk_paint_dispatcher_unittests.cc @@ -64,11 +64,6 @@ TEST(DisplayListUtils, SetColorSourceDoesNotDitherIfNotGradient) { EXPECT_FALSE(helper.paint(true).isDither()); EXPECT_FALSE(helper.paint(false).isDither()); - DlColorColorSource color_color_source(DlColor::kBlue()); - helper.setColorSource(&color_color_source); - EXPECT_FALSE(helper.paint(true).isDither()); - EXPECT_FALSE(helper.paint(false).isDither()); - helper.setColorSource(kTestSource1.get()); EXPECT_FALSE(helper.paint(true).isDither()); EXPECT_FALSE(helper.paint(false).isDither()); @@ -98,13 +93,6 @@ TEST(DisplayListUtils, SkDispatcherSetColorSourceDoesNotDitherIfNotGradient) { EXPECT_FALSE(dispatcher.safe_paint(true)->isDither()); // Calling safe_paint(false) returns a nullptr - DlColorColorSource color_color_source(DlColor::kBlue()); - dispatcher.setColorSource(&color_color_source); - EXPECT_FALSE(dispatcher.paint(true).isDither()); - EXPECT_FALSE(dispatcher.paint(false).isDither()); - EXPECT_FALSE(dispatcher.safe_paint(true)->isDither()); - // Calling safe_paint(false) returns a nullptr - dispatcher.setColorSource(kTestSource1.get()); EXPECT_FALSE(dispatcher.paint(true).isDither()); EXPECT_FALSE(dispatcher.paint(false).isDither()); diff --git a/display_list/testing/dl_rendering_unittests.cc b/display_list/testing/dl_rendering_unittests.cc index 0419c11c48831..bf752442fed9d 100644 --- a/display_list/testing/dl_rendering_unittests.cc +++ b/display_list/testing/dl_rendering_unittests.cc @@ -8,6 +8,7 @@ #include "flutter/display_list/dl_builder.h" #include "flutter/display_list/dl_op_flags.h" #include "flutter/display_list/dl_sampling_options.h" +#include "flutter/display_list/effects/color_filters/dl_matrix_color_filter.h" #include "flutter/display_list/effects/dl_image_filter.h" #include "flutter/display_list/skia/dl_sk_canvas.h" #include "flutter/display_list/skia/dl_sk_conversions.h" @@ -862,7 +863,7 @@ class TestParameters { bool impeller_compatible(const DlPaint& paint) const { if (is_draw_text_blob()) { // Non-color text is rendered as paths - if (paint.getColorSourcePtr() && !paint.getColorSourcePtr()->asColor()) { + if (paint.getColorSourcePtr()) { return false; } // Non-filled text (stroke or stroke and fill) is rendered as paths @@ -1387,7 +1388,8 @@ class CanvasCompareTester { 0, 0, 0, 0.5, 0, }; // clang-format on - DlMatrixColorFilter dl_alpha_rotate_filter(rotate_alpha_color_matrix); + auto dl_alpha_rotate_filter = + DlColorFilter::MakeMatrix(rotate_alpha_color_matrix); auto sk_alpha_rotate_filter = SkColorFilters::Matrix(rotate_alpha_color_matrix); { @@ -1402,7 +1404,7 @@ class CanvasCompareTester { }, [=](const DlSetupContext& ctx) { DlPaint save_p; - save_p.setColorFilter(&dl_alpha_rotate_filter); + save_p.setColorFilter(dl_alpha_rotate_filter); ctx.canvas->SaveLayer(nullptr, &save_p); ctx.paint.setStrokeWidth(5.0); }) @@ -1420,7 +1422,7 @@ class CanvasCompareTester { }, [=](const DlSetupContext& ctx) { DlPaint save_p; - save_p.setColorFilter(&dl_alpha_rotate_filter); + save_p.setColorFilter(dl_alpha_rotate_filter); ctx.canvas->SaveLayer(&kRenderBounds, &save_p); ctx.paint.setStrokeWidth(5.0); }) @@ -1437,8 +1439,8 @@ class CanvasCompareTester { 0, 0, 0, 1, 0, }; // clang-format on - DlMatrixColorFilter dl_color_filter(color_matrix); - DlColorFilterImageFilter dl_cf_image_filter(dl_color_filter); + auto dl_color_filter = DlColorFilter::MakeMatrix(color_matrix); + auto dl_cf_image_filter = DlImageFilter::MakeColorFilter(dl_color_filter); auto sk_cf_image_filter = SkImageFilters::ColorFilter( SkColorFilters::Matrix(color_matrix), nullptr); { @@ -1453,7 +1455,7 @@ class CanvasCompareTester { }, [=](const DlSetupContext& ctx) { DlPaint save_p; - save_p.setImageFilter(&dl_cf_image_filter); + save_p.setImageFilter(dl_cf_image_filter); ctx.canvas->SaveLayer(nullptr, &save_p); ctx.paint.setStrokeWidth(5.0); }) @@ -1471,7 +1473,7 @@ class CanvasCompareTester { }, [=](const DlSetupContext& ctx) { DlPaint save_p; - save_p.setImageFilter(&dl_cf_image_filter); + save_p.setImageFilter(dl_cf_image_filter); ctx.canvas->SaveLayer(&kRenderBounds, &save_p); ctx.paint.setStrokeWidth(5.0); }) @@ -1709,7 +1711,7 @@ class CanvasCompareTester { 1.0, 1.0, 1.0, 1.0, 0, }; // clang-format on - DlMatrixColorFilter dl_color_filter(rotate_color_matrix); + auto dl_color_filter = DlColorFilter::MakeMatrix(rotate_color_matrix); auto sk_color_filter = SkColorFilters::Matrix(rotate_color_matrix); { DlColor bg = DlColor::kWhite(); @@ -1722,7 +1724,7 @@ class CanvasCompareTester { }, [=](const DlSetupContext& ctx) { ctx.paint.setColor(DlColor::kYellow()); - ctx.paint.setColorFilter(&dl_color_filter); + ctx.paint.setColorFilter(dl_color_filter); }) .with_bg(bg)); } @@ -3954,13 +3956,12 @@ TEST_F(DisplayListRendering, SaveLayerConsolidation) { 0.5f, SK_Scalar1, }; - std::vector> color_filters = { - std::make_shared(DlColor::kCyan(), - DlBlendMode::kSrcATop), - std::make_shared(commutable_color_matrix), - std::make_shared(non_commutable_color_matrix), - DlSrgbToLinearGammaColorFilter::kInstance, - DlLinearToSrgbGammaColorFilter::kInstance, + std::vector> color_filters = { + DlColorFilter::MakeBlend(DlColor::kCyan(), DlBlendMode::kSrcATop), + DlColorFilter::MakeMatrix(commutable_color_matrix), + DlColorFilter::MakeMatrix(non_commutable_color_matrix), + DlColorFilter::MakeSrgbToLinearGamma(), + DlColorFilter::MakeLinearToSrgbGamma(), }; std::vector> image_filters = { DlImageFilter::MakeBlur(5.0f, 5.0f, DlTileMode::kDecal), @@ -4131,8 +4132,13 @@ TEST_F(DisplayListRendering, MatrixColorFilterModifyTransparencyCheck) { "matrix[" + std::to_string(element) + "] = " + std::to_string(value); float original_value = matrix[element]; matrix[element] = value; + // Here we instantiate a DlMatrixColorFilter directly so that it is + // not affected by the "NOP" detection in the factory. We sould not + // need to do this if we tested by just rendering the filter color + // over the source color with the filter blend mode instead of + // rendering via a ColorFilter, but this test is more "black box". DlMatrixColorFilter filter(matrix); - auto dl_filter = DlMatrixColorFilter::Make(matrix); + auto dl_filter = DlColorFilter::MakeMatrix(matrix); bool is_identity = (dl_filter == nullptr || original_value == value); DlPaint paint(DlColor(0x7f7f7f7f)); @@ -4200,7 +4206,7 @@ TEST_F(DisplayListRendering, MatrixColorFilterOpacityCommuteCheck) { std::string desc = "matrix[" + std::to_string(element) + "] = " + std::to_string(value); matrix[element] = value; - auto filter = DlMatrixColorFilter::Make(matrix); + auto filter = DlColorFilter::MakeMatrix(matrix); EXPECT_EQ(std::isfinite(value), filter != nullptr); DlPaint paint(DlColor(0x80808080)); @@ -4308,7 +4314,7 @@ TEST_F(DisplayListRendering, BlendColorFilterModifyTransparencyCheck) { std::string desc = desc_str.str(); DlBlendColorFilter filter(color, mode); if (filter.modifies_transparent_black()) { - ASSERT_NE(DlBlendColorFilter::Make(color, mode), nullptr) << desc; + ASSERT_NE(DlColorFilter::MakeBlend(color, mode), nullptr) << desc; } DlPaint paint(DlColor(0x7f7f7f7f)); @@ -4369,7 +4375,7 @@ TEST_F(DisplayListRendering, BlendColorFilterOpacityCommuteCheck) { // If it can commute with opacity, then it might also be a NOP, // so we won't necessarily get a non-null return from |::Make()| } else { - ASSERT_NE(DlBlendColorFilter::Make(color, mode), nullptr) << desc; + ASSERT_NE(DlColorFilter::MakeBlend(color, mode), nullptr) << desc; } DlPaint paint(DlColor(0x80808080)); @@ -4469,8 +4475,8 @@ class DisplayListNopTest : public DisplayListRendering { 0.0001, 0.0001, 0.0001, 0.9997, 0.0, // 0.0001, 0.0001, 0.0001, 0.9997, 0.1, // }; - color_filter_nomtb = DlMatrixColorFilter::Make(color_filter_matrix_nomtb); - color_filter_mtb = DlMatrixColorFilter::Make(color_filter_matrix_mtb); + color_filter_nomtb = DlColorFilter::MakeMatrix(color_filter_matrix_nomtb); + color_filter_mtb = DlColorFilter::MakeMatrix(color_filter_matrix_mtb); EXPECT_FALSE(color_filter_nomtb->modifies_transparent_black()); EXPECT_TRUE(color_filter_mtb->modifies_transparent_black()); @@ -4526,8 +4532,8 @@ class DisplayListNopTest : public DisplayListRendering { std::vector test_src_colors; std::vector test_dst_colors; - std::shared_ptr color_filter_nomtb; - std::shared_ptr color_filter_mtb; + std::shared_ptr color_filter_nomtb; + std::shared_ptr color_filter_mtb; // A 1-row image containing every color in test_dst_colors std::unique_ptr test_data; @@ -4682,7 +4688,7 @@ class DisplayListNopTest : public DisplayListRendering { void test_attributes_image(DlBlendMode mode, DlColor color, - DlColorFilter* color_filter, + const DlColorFilter* color_filter, DlImageFilter* image_filter) { // if (true) { return; } std::stringstream desc_stream; diff --git a/display_list/testing/dl_test_equality.h b/display_list/testing/dl_test_equality.h index 84dcaff5e2814..5fd8c6b370059 100644 --- a/display_list/testing/dl_test_equality.h +++ b/display_list/testing/dl_test_equality.h @@ -12,8 +12,8 @@ namespace flutter { namespace testing { -template -static void TestEquals(T& source1, T& source2) { +template +static void TestEquals(const T& source1, const U& source2) { ASSERT_TRUE(source1 == source2); ASSERT_TRUE(source2 == source1); ASSERT_FALSE(source1 != source2); @@ -24,8 +24,8 @@ static void TestEquals(T& source1, T& source2) { ASSERT_TRUE(Equals(&source2, &source1)); } -template -static void TestNotEquals(T& source1, T& source2, const std::string& label) { +template +static void TestNotEquals(T& source1, U& source2, const std::string& label) { ASSERT_FALSE(source1 == source2) << label; ASSERT_FALSE(source2 == source1) << label; ASSERT_TRUE(source1 != source2) << label; diff --git a/display_list/testing/dl_test_snippets.cc b/display_list/testing/dl_test_snippets.cc index bc348dbaf0063..7e23751f756fc 100644 --- a/display_list/testing/dl_test_snippets.cc +++ b/display_list/testing/dl_test_snippets.cc @@ -220,26 +220,32 @@ std::vector CreateAllAttributesOps() { {"SetColorFilter", { {0, 40, 0, - [](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter1); }}, + [](DlOpReceiver& r) { + r.setColorFilter(kTestBlendColorFilter1.get()); + }}, {0, 40, 0, - [](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter2); }}, + [](DlOpReceiver& r) { + r.setColorFilter(kTestBlendColorFilter2.get()); + }}, {0, 40, 0, - [](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter3); }}, + [](DlOpReceiver& r) { + r.setColorFilter(kTestBlendColorFilter3.get()); + }}, {0, 96, 0, [](DlOpReceiver& r) { - r.setColorFilter(&kTestMatrixColorFilter1); + r.setColorFilter(kTestMatrixColorFilter1.get()); }}, {0, 96, 0, [](DlOpReceiver& r) { - r.setColorFilter(&kTestMatrixColorFilter2); + r.setColorFilter(kTestMatrixColorFilter2.get()); }}, {0, 16, 0, [](DlOpReceiver& r) { - r.setColorFilter(DlSrgbToLinearGammaColorFilter::kInstance.get()); + r.setColorFilter(DlColorFilter::MakeSrgbToLinearGamma().get()); }}, {0, 16, 0, [](DlOpReceiver& r) { - r.setColorFilter(DlLinearToSrgbGammaColorFilter::kInstance.get()); + r.setColorFilter(DlColorFilter::MakeLinearToSrgbGamma().get()); }}, // Reset attribute to default as last entry diff --git a/display_list/testing/dl_test_snippets.h b/display_list/testing/dl_test_snippets.h index c0c5668bfc9a1..08e08e4c64056 100644 --- a/display_list/testing/dl_test_snippets.h +++ b/display_list/testing/dl_test_snippets.h @@ -7,6 +7,7 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/dl_builder.h" +#include "flutter/display_list/effects/color_filters/dl_blend_color_filter.h" #include "flutter/display_list/effects/dl_color_sources.h" #include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/testing/testing.h" @@ -126,14 +127,18 @@ static const std::shared_ptr kTestSource5 = kColors, kStops, DlTileMode::kDecal); -static const DlBlendColorFilter kTestBlendColorFilter1(DlColor::kRed(), - DlBlendMode::kDstATop); -static const DlBlendColorFilter kTestBlendColorFilter2(DlColor::kBlue(), - DlBlendMode::kDstATop); -static const DlBlendColorFilter kTestBlendColorFilter3(DlColor::kRed(), - DlBlendMode::kDstIn); -static const DlMatrixColorFilter kTestMatrixColorFilter1(kRotateColorMatrix); -static const DlMatrixColorFilter kTestMatrixColorFilter2(kInvertColorMatrix); + +static const auto kTestBlendColorFilter1 = + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kDstATop); +static const auto kTestBlendColorFilter2 = + DlColorFilter::MakeBlend(DlColor::kBlue(), DlBlendMode::kDstATop); +static const auto kTestBlendColorFilter3 = + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kDstOver); +static const auto kTestMatrixColorFilter1 = + DlColorFilter::MakeMatrix(kRotateColorMatrix); +static const auto kTestMatrixColorFilter2 = + DlColorFilter::MakeMatrix(kInvertColorMatrix); + static const DlBlurImageFilter kTestBlurImageFilter1(5.0, 5.0, DlTileMode::kClamp); diff --git a/display_list/utils/dl_comparable.h b/display_list/utils/dl_comparable.h index 6273bc703f70f..008da8d9942c3 100644 --- a/display_list/utils/dl_comparable.h +++ b/display_list/utils/dl_comparable.h @@ -15,8 +15,8 @@ namespace flutter { // Any combination of shared_ptr or T* are supported and null pointers // are not equal to anything but another null pointer. -template -bool Equals(const T* a, const T* b) { +template +bool Equals(const T* a, const U* b) { if (a == b) { return true; } @@ -26,88 +26,88 @@ bool Equals(const T* a, const T* b) { return *a == *b; } -template -bool Equals(std::shared_ptr a, const T* b) { +template +bool Equals(std::shared_ptr a, const U* b) { return Equals(a.get(), b); } -template -bool Equals(std::shared_ptr a, const T* b) { +template +bool Equals(std::shared_ptr a, const U* b) { return Equals(a.get(), b); } -template -bool Equals(const T* a, std::shared_ptr b) { +template +bool Equals(const T* a, std::shared_ptr b) { return Equals(a, b.get()); } -template -bool Equals(const T* a, std::shared_ptr b) { +template +bool Equals(const T* a, std::shared_ptr b) { return Equals(a, b.get()); } -template -bool Equals(std::shared_ptr a, std::shared_ptr b) { +template +bool Equals(std::shared_ptr a, std::shared_ptr b) { return Equals(a.get(), b.get()); } -template -bool Equals(std::shared_ptr a, std::shared_ptr b) { +template +bool Equals(std::shared_ptr a, std::shared_ptr b) { return Equals(a.get(), b.get()); } -template -bool Equals(std::shared_ptr a, std::shared_ptr b) { +template +bool Equals(std::shared_ptr a, std::shared_ptr b) { return Equals(a.get(), b.get()); } -template -bool Equals(std::shared_ptr a, std::shared_ptr b) { +template +bool Equals(std::shared_ptr a, std::shared_ptr b) { return Equals(a.get(), b.get()); } -template -bool NotEquals(const T* a, const T* b) { - return !Equals(a, b); +template +bool NotEquals(const T* a, const U* b) { + return !Equals(a, b); } -template -bool NotEquals(std::shared_ptr a, const T* b) { +template +bool NotEquals(std::shared_ptr a, const U* b) { return !Equals(a.get(), b); } -template -bool NotEquals(std::shared_ptr a, const T* b) { +template +bool NotEquals(std::shared_ptr a, const U* b) { return !Equals(a.get(), b); } -template -bool NotEquals(const T* a, std::shared_ptr b) { +template +bool NotEquals(const T* a, std::shared_ptr b) { return !Equals(a, b.get()); } -template -bool NotEquals(const T* a, std::shared_ptr b) { +template +bool NotEquals(const T* a, std::shared_ptr b) { return !Equals(a, b.get()); } -template -bool NotEquals(std::shared_ptr a, std::shared_ptr b) { +template +bool NotEquals(std::shared_ptr a, std::shared_ptr b) { return !Equals(a.get(), b.get()); } -template -bool NotEquals(std::shared_ptr a, std::shared_ptr b) { +template +bool NotEquals(std::shared_ptr a, std::shared_ptr b) { return !Equals(a.get(), b.get()); } -template -bool NotEquals(std::shared_ptr a, std::shared_ptr b) { +template +bool NotEquals(std::shared_ptr a, std::shared_ptr b) { return !Equals(a.get(), b.get()); } -template -bool NotEquals(std::shared_ptr a, std::shared_ptr b) { +template +bool NotEquals(std::shared_ptr a, std::shared_ptr b) { return !Equals(a.get(), b.get()); } diff --git a/flow/layers/color_filter_layer_unittests.cc b/flow/layers/color_filter_layer_unittests.cc index 209ca2b22733a..c43ca5d6f9ac6 100644 --- a/flow/layers/color_filter_layer_unittests.cc +++ b/flow/layers/color_filter_layer_unittests.cc @@ -89,7 +89,7 @@ TEST_F(ColorFilterLayerTest, SimpleFilter) { const SkPath child_path = SkPath().addRect(child_bounds); const DlPaint child_paint = DlPaint(DlColor::kYellow()); - auto dl_color_filter = DlLinearToSrgbGammaColorFilter::kInstance; + auto dl_color_filter = DlColorFilter::MakeLinearToSrgbGamma(); auto mock_layer = std::make_shared(child_path, child_paint); auto layer = std::make_shared(dl_color_filter); layer->Add(mock_layer); @@ -129,7 +129,7 @@ TEST_F(ColorFilterLayerTest, MultipleChildren) { const DlPaint child_paint2 = DlPaint(DlColor::kCyan()); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); - auto dl_color_filter = DlSrgbToLinearGammaColorFilter::kInstance; + auto dl_color_filter = DlColorFilter::MakeSrgbToLinearGamma(); auto layer = std::make_shared(dl_color_filter); layer->Add(mock_layer1); layer->Add(mock_layer2); @@ -179,7 +179,7 @@ TEST_F(ColorFilterLayerTest, Nested) { const DlPaint child_paint2 = DlPaint(DlColor::kCyan()); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); - auto dl_color_filter = DlSrgbToLinearGammaColorFilter::kInstance; + auto dl_color_filter = DlColorFilter::MakeSrgbToLinearGamma(); auto layer1 = std::make_shared(dl_color_filter); auto layer2 = std::make_shared(dl_color_filter); @@ -239,7 +239,7 @@ TEST_F(ColorFilterLayerTest, Readback) { // ColorFilterLayer does not read from surface auto layer = std::make_shared( - DlLinearToSrgbGammaColorFilter::kInstance); + DlColorFilter::MakeLinearToSrgbGamma()); preroll_context()->surface_needs_readback = false; preroll_context()->state_stack.set_preroll_delegate(initial_transform); layer->Preroll(preroll_context()); @@ -255,7 +255,7 @@ TEST_F(ColorFilterLayerTest, Readback) { } TEST_F(ColorFilterLayerTest, CacheChild) { - auto layer_filter = DlSrgbToLinearGammaColorFilter::kInstance; + auto layer_filter = DlColorFilter::MakeSrgbToLinearGamma(); auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); @@ -296,7 +296,7 @@ TEST_F(ColorFilterLayerTest, CacheChild) { } TEST_F(ColorFilterLayerTest, CacheChildren) { - auto layer_filter = DlSrgbToLinearGammaColorFilter::kInstance; + auto layer_filter = DlColorFilter::MakeSrgbToLinearGamma(); auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); @@ -342,7 +342,7 @@ TEST_F(ColorFilterLayerTest, CacheChildren) { } TEST_F(ColorFilterLayerTest, CacheColorFilterLayerSelf) { - auto layer_filter = DlSrgbToLinearGammaColorFilter::kInstance; + auto layer_filter = DlColorFilter::MakeSrgbToLinearGamma(); auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); @@ -408,12 +408,12 @@ TEST_F(ColorFilterLayerTest, OpacityInheritance) { 0, 0, 0, 1, 0, }; // clang-format on - auto layer_filter = DlMatrixColorFilter(matrix); + auto layer_filter = DlColorFilter::MakeMatrix(matrix); auto initial_transform = SkMatrix::Translate(50.0, 25.5); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); auto mock_layer = std::make_shared(child_path); - auto color_filter_layer = std::make_shared( - std::make_shared(matrix)); + auto color_filter_layer = + std::make_shared(DlColorFilter::MakeMatrix(matrix)); color_filter_layer->Add(mock_layer); PrerollContext* context = preroll_context(); @@ -440,7 +440,7 @@ TEST_F(ColorFilterLayerTest, OpacityInheritance) { /* ColorFilterLayer::Paint() */ { DlPaint dl_paint; dl_paint.setColor(DlColor(opacity_alpha << 24)); - dl_paint.setColorFilter(&layer_filter); + dl_paint.setColorFilter(layer_filter); expected_builder.SaveLayer(&child_path.getBounds(), &dl_paint); /* MockLayer::Paint() */ { expected_builder.DrawPath(child_path, DlPaint(DlColor(0xFF000000))); diff --git a/flow/layers/layer_state_stack_unittests.cc b/flow/layers/layer_state_stack_unittests.cc index 4e3f092270d9b..bffe21ccf7750 100644 --- a/flow/layers/layer_state_stack_unittests.cc +++ b/flow/layers/layer_state_stack_unittests.cc @@ -207,12 +207,10 @@ TEST(LayerStateStack, Opacity) { TEST(LayerStateStack, ColorFilter) { SkRect rect = {10, 10, 20, 20}; - std::shared_ptr outer_filter = - std::make_shared(DlColor::kYellow(), - DlBlendMode::kColorBurn); - std::shared_ptr inner_filter = - std::make_shared(DlColor::kRed(), - DlBlendMode::kColorBurn); + auto outer_filter = + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kColorBurn); + auto inner_filter = + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kColorBurn); LayerStateStack state_stack; state_stack.set_preroll_delegate(SkRect::MakeLTRB(0, 0, 50, 50)); @@ -370,9 +368,8 @@ TEST(LayerStateStack, ImageFilter) { TEST(LayerStateStack, OpacityAndColorFilterInteraction) { SkRect rect = {10, 10, 20, 20}; - std::shared_ptr color_filter = - std::make_shared(DlColor::kYellow(), - DlBlendMode::kColorBurn); + auto color_filter = + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kColorBurn); DisplayListBuilder builder; LayerStateStack state_stack; @@ -489,11 +486,9 @@ TEST(LayerStateStack, OpacityAndImageFilterInteraction) { TEST(LayerStateStack, ColorFilterAndImageFilterInteraction) { SkRect rect = {10, 10, 20, 20}; - std::shared_ptr color_filter = - std::make_shared(DlColor::kYellow(), - DlBlendMode::kColorBurn); - std::shared_ptr image_filter = - DlImageFilter::MakeBlur(2.0f, 2.0f, DlTileMode::kClamp); + auto color_filter = + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kColorBurn); + auto image_filter = DlImageFilter::MakeBlur(2.0f, 2.0f, DlTileMode::kClamp); DisplayListBuilder builder; LayerStateStack state_stack; diff --git a/flow/paint_region.h b/flow/paint_region.h index 52f29762f67ad..34b7ac1e9bbeb 100644 --- a/flow/paint_region.h +++ b/flow/paint_region.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_FLOW_PAINT_REGION_H_ #define FLUTTER_FLOW_PAINT_REGION_H_ +#include #include #include #include "flutter/fml/logging.h" diff --git a/flutter_frontend_server/pubspec.yaml b/flutter_frontend_server/pubspec.yaml index 3cb88d8a9aff1..4fb0fc42d1c5e 100644 --- a/flutter_frontend_server/pubspec.yaml +++ b/flutter_frontend_server/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/fml/cpu_affinity.cc b/fml/cpu_affinity.cc index 0342c85f0433e..a580c9d04c52c 100644 --- a/fml/cpu_affinity.cc +++ b/fml/cpu_affinity.cc @@ -5,6 +5,7 @@ #include "flutter/fml/cpu_affinity.h" #include "flutter/fml/build_config.h" +#include #include #include #include diff --git a/fml/cpu_affinity.h b/fml/cpu_affinity.h index c1d8498e6524a..c644472965d41 100644 --- a/fml/cpu_affinity.h +++ b/fml/cpu_affinity.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_FML_CPU_AFFINITY_H_ #define FLUTTER_FML_CPU_AFFINITY_H_ +#include #include #include #include diff --git a/fml/synchronization/sync_switch.cc b/fml/synchronization/sync_switch.cc index 463b6a08d75ad..9421e30e0461b 100644 --- a/fml/synchronization/sync_switch.cc +++ b/fml/synchronization/sync_switch.cc @@ -5,6 +5,7 @@ #include "flutter/fml/synchronization/sync_switch.h" #include +#include namespace fml { diff --git a/fml/task_runner.cc b/fml/task_runner.cc index 5f9dd019c685e..8920a8f73ab25 100644 --- a/fml/task_runner.cc +++ b/fml/task_runner.cc @@ -52,6 +52,7 @@ bool TaskRunner::RunsTasksOnCurrentThread() { loop_queue_id); } +// static void TaskRunner::RunNowOrPostTask(const fml::RefPtr& runner, const fml::closure& task) { FML_DCHECK(runner); @@ -62,4 +63,20 @@ void TaskRunner::RunNowOrPostTask(const fml::RefPtr& runner, } } +// static +void TaskRunner::RunNowAndFlushMessages( + const fml::RefPtr& runner, + const fml::closure& task) { + FML_DCHECK(runner); + if (runner->RunsTasksOnCurrentThread()) { + task(); + // Post an empty task to make the UI message loop run its task observers. + // The observers will execute any Dart microtasks queued by the platform + // message handler. + runner->PostTask([] {}); + } else { + runner->PostTask(task); + } +} + } // namespace fml diff --git a/fml/task_runner.h b/fml/task_runner.h index 885c1b3efb566..6bc1c1a06cd8a 100644 --- a/fml/task_runner.h +++ b/fml/task_runner.h @@ -62,6 +62,14 @@ class TaskRunner : public fml::RefCountedThreadSafe, static void RunNowOrPostTask(const fml::RefPtr& runner, const fml::closure& task); + /// Like RunNowOrPostTask, except that if the task can be immediately + /// executed, an empty task will still be posted to the runner afterwards. + /// + /// This is used to ensure that messages posted to Dart from the platform + /// thread always flush the Dart event loop. + static void RunNowAndFlushMessages(const fml::RefPtr& runner, + const fml::closure& task); + protected: explicit TaskRunner(fml::RefPtr loop); diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 6c6b90e763fc2..15246a28d5d67 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -159,7 +159,7 @@ struct {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader { {% endfor %}) { return {{ proto.args.0.argument_name }}.BindResource({% for arg in proto.args %} {% if loop.is_first %} -{{to_shader_stage(shader_stage)}}, {{ proto.descriptor_type }}, kResource{{ proto.name }}, kMetadata{{ proto.name }}, {% else %} +{{to_shader_stage(shader_stage)}}, {{ proto.descriptor_type }}, kResource{{ proto.name }}, &kMetadata{{ proto.name }}, {% else %} std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} {% endif %} {% endfor %}); diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index 6123ad3f15982..9d7fdbf152f24 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -26,6 +26,12 @@ namespace impeller { namespace compiler { +namespace { +constexpr const char* kEGLImageExternalExtension = "GL_OES_EGL_image_external"; +constexpr const char* kEGLImageExternalExtension300 = + "GL_OES_EGL_image_external_essl3"; +} // namespace + static uint32_t ParseMSLVersion(const std::string& msl_version) { std::stringstream sstream(msl_version); std::string version_part; @@ -147,7 +153,11 @@ static CompilerBackend CreateGLSLCompiler(const spirv_cross::ParsedIR& ir, // incompatible with ES 310+. for (auto& id : ir.ids_for_constant_or_variable) { if (StringStartsWith(ir.get_name(id), kExternalTexturePrefix)) { - gl_compiler->require_extension("GL_OES_EGL_image_external"); + if (source_options.gles_language_version >= 300) { + gl_compiler->require_extension(kEGLImageExternalExtension300); + } else { + gl_compiler->require_extension(kEGLImageExternalExtension); + } break; } } @@ -156,11 +166,15 @@ static CompilerBackend CreateGLSLCompiler(const spirv_cross::ParsedIR& ir, sl_options.force_zero_initialized_variables = true; sl_options.vertex.fixup_clipspace = true; if (source_options.target_platform == TargetPlatform::kOpenGLES || - source_options.target_platform == TargetPlatform::kRuntimeStageGLES) { + source_options.target_platform == TargetPlatform::kRuntimeStageGLES || + source_options.target_platform == TargetPlatform::kRuntimeStageGLES3) { sl_options.version = source_options.gles_language_version > 0 ? source_options.gles_language_version : 100; sl_options.es = true; + if (source_options.target_platform == TargetPlatform::kRuntimeStageGLES3) { + sl_options.version = 300; + } if (source_options.require_framebuffer_fetch && source_options.type == SourceType::kFragmentShader) { gl_compiler->remap_ext_framebuffer_fetch(0, 0, true); @@ -202,6 +216,7 @@ static bool EntryPointMustBeNamedMain(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: return true; } FML_UNREACHABLE(); @@ -224,6 +239,7 @@ static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir, case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: compiler = CreateGLSLCompiler(ir, source_options); break; case TargetPlatform::kSkSL: @@ -317,7 +333,8 @@ Compiler::Compiler(const std::shared_ptr& source_mapping, spirv_options.target = target; } break; case TargetPlatform::kRuntimeStageMetal: - case TargetPlatform::kRuntimeStageGLES: { + case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: { SPIRVCompilerTargetEnv target; target.env = shaderc_target_env::shaderc_target_env_opengl; diff --git a/impeller/compiler/impellerc_main.cc b/impeller/compiler/impellerc_main.cc index a0535a2882b04..e4b54350378f0 100644 --- a/impeller/compiler/impellerc_main.cc +++ b/impeller/compiler/impellerc_main.cc @@ -207,6 +207,7 @@ static bool OutputDepfile(const Compiler& compiler, const Switches& switches) { case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageMetal: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: case TargetPlatform::kSkSL: case TargetPlatform::kVulkan: diff --git a/impeller/compiler/reflector.cc b/impeller/compiler/reflector.cc index 23792ea6924ba..5f9ba45eb1f48 100644 --- a/impeller/compiler/reflector.cc +++ b/impeller/compiler/reflector.cc @@ -312,6 +312,8 @@ static std::optional GetRuntimeStageBackend( return RuntimeStageBackend::kMetal; case TargetPlatform::kRuntimeStageGLES: return RuntimeStageBackend::kOpenGLES; + case TargetPlatform::kRuntimeStageGLES3: + return RuntimeStageBackend::kOpenGLES3; case TargetPlatform::kRuntimeStageVulkan: return RuntimeStageBackend::kVulkan; case TargetPlatform::kSkSL: diff --git a/impeller/compiler/runtime_stage_data.cc b/impeller/compiler/runtime_stage_data.cc index b45926305f55b..c7b28a6184fc4 100644 --- a/impeller/compiler/runtime_stage_data.cc +++ b/impeller/compiler/runtime_stage_data.cc @@ -204,6 +204,8 @@ static std::string RuntimeStageBackendToString(RuntimeStageBackend backend) { return "opengles"; case RuntimeStageBackend::kVulkan: return "vulkan"; + case RuntimeStageBackend::kOpenGLES3: + return "opengles3"; } } @@ -384,6 +386,9 @@ RuntimeStageData::CreateMultiStageFlatbuffer() const { case RuntimeStageBackend::kVulkan: runtime_stages->vulkan = std::move(runtime_stage); break; + case RuntimeStageBackend::kOpenGLES3: + runtime_stages->opengles3 = std::move(runtime_stage); + break; } } return runtime_stages; diff --git a/impeller/compiler/switches.cc b/impeller/compiler/switches.cc index 31ae741707864..1dba36b211804 100644 --- a/impeller/compiler/switches.cc +++ b/impeller/compiler/switches.cc @@ -29,6 +29,7 @@ static const std::map kKnownRuntimeStages = { {"sksl", TargetPlatform::kSkSL}, {"runtime-stage-metal", TargetPlatform::kRuntimeStageMetal}, {"runtime-stage-gles", TargetPlatform::kRuntimeStageGLES}, + {"runtime-stage-gles3", TargetPlatform::kRuntimeStageGLES3}, {"runtime-stage-vulkan", TargetPlatform::kRuntimeStageVulkan}, }; diff --git a/impeller/compiler/types.cc b/impeller/compiler/types.cc index 2368bcd20fbec..85e197b99dbe3 100644 --- a/impeller/compiler/types.cc +++ b/impeller/compiler/types.cc @@ -89,6 +89,8 @@ std::string TargetPlatformToString(TargetPlatform platform) { return "RuntimeStageMetal"; case TargetPlatform::kRuntimeStageGLES: return "RuntimeStageGLES"; + case TargetPlatform::kRuntimeStageGLES3: + return "RuntimeStageGLES3"; case TargetPlatform::kRuntimeStageVulkan: return "RuntimeStageVulkan"; case TargetPlatform::kSkSL: @@ -146,6 +148,7 @@ bool TargetPlatformNeedsReflection(TargetPlatform platform) { case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageMetal: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: case TargetPlatform::kVulkan: return true; @@ -221,6 +224,7 @@ spirv_cross::CompilerMSL::Options::Platform TargetPlatformToMSLPlatform( case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: case TargetPlatform::kVulkan: case TargetPlatform::kUnknown: @@ -255,6 +259,7 @@ std::string TargetPlatformSLExtension(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: return "glsl"; case TargetPlatform::kVulkan: case TargetPlatform::kRuntimeStageVulkan: @@ -268,6 +273,7 @@ bool TargetPlatformIsOpenGL(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: return true; case TargetPlatform::kMetalDesktop: case TargetPlatform::kRuntimeStageMetal: @@ -292,6 +298,7 @@ bool TargetPlatformIsMetal(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: case TargetPlatform::kVulkan: return false; @@ -312,6 +319,7 @@ bool TargetPlatformIsVulkan(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: return false; } FML_UNREACHABLE(); @@ -322,6 +330,7 @@ bool TargetPlatformBundlesSkSL(TargetPlatform platform) { case TargetPlatform::kSkSL: case TargetPlatform::kRuntimeStageMetal: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: return true; case TargetPlatform::kMetalDesktop: diff --git a/impeller/compiler/types.h b/impeller/compiler/types.h index 81b631d49eec7..3878d0cef6d5c 100644 --- a/impeller/compiler/types.h +++ b/impeller/compiler/types.h @@ -34,6 +34,7 @@ enum class TargetPlatform { kVulkan, kRuntimeStageMetal, kRuntimeStageGLES, + kRuntimeStageGLES3, kRuntimeStageVulkan, kSkSL, }; diff --git a/impeller/core/resource_binder.h b/impeller/core/resource_binder.h index 8f25ff0c7fe18..120d8c969634f 100644 --- a/impeller/core/resource_binder.h +++ b/impeller/core/resource_binder.h @@ -26,13 +26,13 @@ struct ResourceBinder { virtual bool BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) = 0; virtual bool BindResource(ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) = 0; }; diff --git a/impeller/core/runtime_types.h b/impeller/core/runtime_types.h index b38d61b0eb87a..84eb052991ab8 100644 --- a/impeller/core/runtime_types.h +++ b/impeller/core/runtime_types.h @@ -6,6 +6,7 @@ #define FLUTTER_IMPELLER_CORE_RUNTIME_TYPES_H_ #include +#include #include #include #include @@ -16,6 +17,7 @@ enum class RuntimeStageBackend { kSkSL, kMetal, kOpenGLES, + kOpenGLES3, kVulkan, }; diff --git a/impeller/core/sampler_descriptor.cc b/impeller/core/sampler_descriptor.cc index 9e99089813dd3..5f668bb1bd987 100644 --- a/impeller/core/sampler_descriptor.cc +++ b/impeller/core/sampler_descriptor.cc @@ -4,19 +4,17 @@ #include "impeller/core/sampler_descriptor.h" -#include "fml/logging.h" - namespace impeller { SamplerDescriptor::SamplerDescriptor() = default; -SamplerDescriptor::SamplerDescriptor(std::string label, +SamplerDescriptor::SamplerDescriptor(std::string_view label, MinMagFilter min_filter, MinMagFilter mag_filter, MipFilter mip_filter) : min_filter(min_filter), mag_filter(mag_filter), mip_filter(mip_filter), - label(std::move(label)) {} + label(label) {} } // namespace impeller diff --git a/impeller/core/sampler_descriptor.h b/impeller/core/sampler_descriptor.h index 0e92745ec311f..31e91c129a9db 100644 --- a/impeller/core/sampler_descriptor.h +++ b/impeller/core/sampler_descriptor.h @@ -21,11 +21,11 @@ struct SamplerDescriptor final : public Comparable { SamplerAddressMode height_address_mode = SamplerAddressMode::kClampToEdge; SamplerAddressMode depth_address_mode = SamplerAddressMode::kClampToEdge; - std::string label = "NN Clamp Sampler"; + std::string_view label = "NN Clamp Sampler"; SamplerDescriptor(); - SamplerDescriptor(std::string label, + SamplerDescriptor(std::string_view label, MinMagFilter min_filter, MinMagFilter mag_filter, MipFilter mip_filter); diff --git a/impeller/display_list/aiks_dl_basic_unittests.cc b/impeller/display_list/aiks_dl_basic_unittests.cc index d62d2ace32686..281a33e7d09d6 100644 --- a/impeller/display_list/aiks_dl_basic_unittests.cc +++ b/impeller/display_list/aiks_dl_basic_unittests.cc @@ -58,7 +58,7 @@ TEST_P(AiksTest, CanRenderInvertedImageWithColorFilter) { DlPaint paint; paint.setColor(DlColor::kRed()); paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kYellow(), DlBlendMode::kSrcOver)); + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver)); paint.setInvertColors(true); auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg")); @@ -72,7 +72,7 @@ TEST_P(AiksTest, CanRenderColorFilterWithInvertColors) { DlPaint paint; paint.setColor(DlColor::kRed()); paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kYellow(), DlBlendMode::kSrcOver)); + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver)); paint.setInvertColors(true); builder.DrawRect(SkRect::MakeLTRB(0, 0, 100, 100), paint); @@ -84,7 +84,7 @@ TEST_P(AiksTest, CanRenderColorFilterWithInvertColorsDrawPaint) { DlPaint paint; paint.setColor(DlColor::kRed()); paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kYellow(), DlBlendMode::kSrcOver)); + DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver)); paint.setInvertColors(true); builder.DrawPaint(paint); @@ -829,7 +829,7 @@ TEST_P(AiksTest, CanRenderClippedBackdropFilter) { DlPaint save_paint; auto backdrop_filter = DlImageFilter::MakeColorFilter( - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kExclusion)); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kExclusion)); builder.SaveLayer(&clip_rect, &save_paint, backdrop_filter.get()); ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); @@ -1513,7 +1513,7 @@ TEST_P(AiksTest, PipelineBlendSingleParameter) { paint.setColor(DlColor::kGreen()); paint.setBlendMode(DlBlendMode::kSrcOver); paint.setImageFilter(DlImageFilter::MakeColorFilter( - DlBlendColorFilter::Make(DlColor::kWhite(), DlBlendMode::kDst))); + DlColorFilter::MakeBlend(DlColor::kWhite(), DlBlendMode::kDst))); builder.DrawCircle(SkPoint::Make(200, 200), 200, paint); builder.Restore(); } diff --git a/impeller/display_list/aiks_dl_blend_unittests.cc b/impeller/display_list/aiks_dl_blend_unittests.cc index 143ef8312eac4..062a61b3f2b20 100644 --- a/impeller/display_list/aiks_dl_blend_unittests.cc +++ b/impeller/display_list/aiks_dl_blend_unittests.cc @@ -66,7 +66,7 @@ TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer) { builder.ClipRect(layer_rect); DlPaint save_paint; - save_paint.setColorFilter(DlBlendColorFilter::Make( + save_paint.setColorFilter(DlColorFilter::MakeBlend( DlColor::RGBA(0, 1, 0, 0.5), DlBlendMode::kDifference)); builder.SaveLayer(&layer_rect, &save_paint); @@ -233,7 +233,7 @@ TEST_P(AiksTest, ColorFilterBlend) { srcPaint.setBlendMode(blend_modes[i]); if (has_color_filter) { std::shared_ptr color_filter = - DlBlendColorFilter::Make(DlColor::RGBA(0.9, 0.5, 0.0, 1.0), + DlColorFilter::MakeBlend(DlColor::RGBA(0.9, 0.5, 0.0, 1.0), DlBlendMode::kSrcIn); srcPaint.setColorFilter(color_filter); } @@ -290,7 +290,7 @@ TEST_P(AiksTest, ColorFilterAdvancedBlend) { srcPaint.setBlendMode(blend_modes[i]); if (has_color_filter) { std::shared_ptr color_filter = - DlBlendColorFilter::Make(DlColor::RGBA(0.9, 0.5, 0.0, 1.0), + DlColorFilter::MakeBlend(DlColor::RGBA(0.9, 0.5, 0.0, 1.0), DlBlendMode::kSrcIn); srcPaint.setColorFilter(color_filter); } @@ -382,7 +382,7 @@ TEST_P(AiksTest, ColorFilterAdvancedBlendNoFbFetch) { srcPaint.setBlendMode(blend_modes[i]); if (has_color_filter) { std::shared_ptr color_filter = - DlBlendColorFilter::Make(DlColor::RGBA(0.9, 0.5, 0.0, 1.0), + DlColorFilter::MakeBlend(DlColor::RGBA(0.9, 0.5, 0.0, 1.0), DlBlendMode::kMultiply); srcPaint.setColorFilter(color_filter); } @@ -445,7 +445,7 @@ TEST_P(AiksTest, BlendModePlusAlphaColorFilterWideGamut) { DlPaint save_paint; save_paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::RGBA(1, 0, 0, 1), DlBlendMode::kPlus)); + DlColorFilter::MakeBlend(DlColor::RGBA(1, 0, 0, 1), DlBlendMode::kPlus)); builder.SaveLayer(nullptr, &save_paint); paint.setColor(DlColor::kRed()); @@ -471,7 +471,7 @@ TEST_P(AiksTest, ForegroundBlendSubpassCollapseOptimization) { DlPaint save_paint; save_paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kColorDodge)); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kColorDodge)); builder.SaveLayer(nullptr, &save_paint); builder.Translate(500, 300); @@ -721,7 +721,7 @@ TEST_P(AiksTest, ForegroundPipelineBlendAppliesTransformCorrectly) { builder.Rotate(30); DlPaint image_paint; - image_paint.setColorFilter(DlBlendColorFilter::Make( + image_paint.setColorFilter(DlColorFilter::MakeBlend( DlColor::RGBA(255.0f / 255.0f, 165.0f / 255.0f, 0.0f / 255.0f, 1.0f), DlBlendMode::kSrcIn)); @@ -739,7 +739,7 @@ TEST_P(AiksTest, ForegroundAdvancedBlendAppliesTransformCorrectly) { builder.Rotate(30); DlPaint image_paint; - image_paint.setColorFilter(DlBlendColorFilter::Make( + image_paint.setColorFilter(DlColorFilter::MakeBlend( DlColor::RGBA(255.0f / 255.0f, 165.0f / 255.0f, 0.0f / 255.0f, 1.0f), DlBlendMode::kColorDodge)); @@ -898,7 +898,7 @@ TEST_P(AiksTest, DestructiveBlendColorFilterFloodsClip) { DlPaint save_paint; save_paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kSrc)); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc)); builder.SaveLayer(nullptr, &save_paint); builder.Restore(); @@ -913,7 +913,7 @@ TEST_P(AiksTest, AdvancedBlendColorFilterWithDestinationOpacity) { DlPaint save_paint; save_paint.setOpacity(0.3); - save_paint.setColorFilter(DlBlendColorFilter::Make(DlColor::kTransparent(), + save_paint.setColorFilter(DlColorFilter::MakeBlend(DlColor::kTransparent(), DlBlendMode::kSaturation)); builder.SaveLayer(nullptr, &save_paint); builder.DrawRect(SkRect::MakeXYWH(100, 100, 300, 300), diff --git a/impeller/display_list/aiks_dl_blur_unittests.cc b/impeller/display_list/aiks_dl_blur_unittests.cc index 00d126560fbc6..63a3d5443acb6 100644 --- a/impeller/display_list/aiks_dl_blur_unittests.cc +++ b/impeller/display_list/aiks_dl_blur_unittests.cc @@ -175,7 +175,7 @@ TEST_P(AiksTest, CanRenderForegroundBlendWithMaskBlur) { paint.setMaskFilter( DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma.sigma)); paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kGreen(), DlBlendMode::kSrc)); + DlColorFilter::MakeBlend(DlColor::kGreen(), DlBlendMode::kSrc)); builder.DrawCircle(SkPoint{400, 400}, 200, paint); ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); @@ -195,7 +195,7 @@ TEST_P(AiksTest, CanRenderForegroundAdvancedBlendWithMaskBlur) { paint.setMaskFilter( DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma.sigma)); paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kGreen(), DlBlendMode::kColor)); + DlColorFilter::MakeBlend(DlColor::kGreen(), DlBlendMode::kColor)); builder.DrawCircle(SkPoint{400, 400}, 200, paint); builder.Restore(); diff --git a/impeller/display_list/aiks_dl_gradient_unittests.cc b/impeller/display_list/aiks_dl_gradient_unittests.cc index 7e362015441a0..2f9c0f27ae65c 100644 --- a/impeller/display_list/aiks_dl_gradient_unittests.cc +++ b/impeller/display_list/aiks_dl_gradient_unittests.cc @@ -94,7 +94,7 @@ TEST_P(AiksTest, CanRenderLinearGradientDecalWithColorFilter) { // Overlay the gradient with 25% green. This should appear as the entire // rectangle being drawn with 25% green, including the border area outside the // decal gradient. - paint.setColorFilter(DlBlendColorFilter::Make(DlColor::kGreen().withAlpha(64), + paint.setColorFilter(DlColorFilter::MakeBlend(DlColor::kGreen().withAlpha(64), DlBlendMode::kSrcOver)); paint.setColor(DlColor::kWhite()); builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint); diff --git a/impeller/display_list/aiks_dl_path_unittests.cc b/impeller/display_list/aiks_dl_path_unittests.cc index 1d9d8528365b6..953f193be9a6c 100644 --- a/impeller/display_list/aiks_dl_path_unittests.cc +++ b/impeller/display_list/aiks_dl_path_unittests.cc @@ -38,7 +38,7 @@ TEST_P(AiksTest, RotateColorFilteredPath) { arrow_head.moveTo({50, 120}).lineTo({120, 190}).lineTo({190, 120}); auto filter = - DlBlendColorFilter::Make(DlColor::kAliceBlue(), DlBlendMode::kSrcIn); + DlColorFilter::MakeBlend(DlColor::kAliceBlue(), DlBlendMode::kSrcIn); DlPaint paint; paint.setStrokeWidth(15.0); diff --git a/impeller/display_list/aiks_dl_unittests.cc b/impeller/display_list/aiks_dl_unittests.cc index 0849f9b9a057c..6c389981031f2 100644 --- a/impeller/display_list/aiks_dl_unittests.cc +++ b/impeller/display_list/aiks_dl_unittests.cc @@ -87,7 +87,7 @@ TEST_P(AiksTest, ColorMatrixFilterSubpassCollapseOptimization) { 0, 0, -1.0, 1.0, 0, // 1.0, 1.0, 1.0, 1.0, 0 // }; - auto filter = DlMatrixColorFilter::Make(matrix); + auto filter = DlColorFilter::MakeMatrix(matrix); DlPaint paint; paint.setColorFilter(filter); @@ -107,7 +107,7 @@ TEST_P(AiksTest, LinearToSrgbFilterSubpassCollapseOptimization) { DisplayListBuilder builder(GetCullRect(GetWindowSize())); DlPaint paint; - paint.setColorFilter(DlLinearToSrgbGammaColorFilter::kInstance); + paint.setColorFilter(DlColorFilter::MakeLinearToSrgbGamma()); builder.SaveLayer(nullptr, &paint); builder.Translate(500, 300); @@ -124,7 +124,7 @@ TEST_P(AiksTest, SrgbToLinearFilterSubpassCollapseOptimization) { DisplayListBuilder builder(GetCullRect(GetWindowSize())); DlPaint paint; - paint.setColorFilter(DlLinearToSrgbGammaColorFilter::kInstance); + paint.setColorFilter(DlColorFilter::MakeLinearToSrgbGamma()); builder.SaveLayer(nullptr, &paint); builder.Translate(500, 300); @@ -163,7 +163,7 @@ TEST_P(AiksTest, TranslucentSaveLayerWithBlendColorFilterDrawsCorrectly) { DlPaint save_paint; paint.setColor(DlColor::kBlack().withAlpha(128)); paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kDstOver)); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kDstOver)); builder.Save(); builder.ClipRect(SkRect::MakeXYWH(100, 500, 300, 300)); builder.SaveLayer(nullptr, &paint); @@ -187,7 +187,7 @@ TEST_P(AiksTest, TranslucentSaveLayerWithBlendImageFilterDrawsCorrectly) { DlPaint save_paint; save_paint.setColor(DlColor::kBlack().withAlpha(128)); save_paint.setImageFilter(DlImageFilter::MakeColorFilter( - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kDstOver))); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kDstOver))); builder.SaveLayer(nullptr, &save_paint); @@ -209,7 +209,7 @@ TEST_P(AiksTest, TranslucentSaveLayerWithColorAndImageFilterDrawsCorrectly) { DlPaint save_paint; save_paint.setColor(DlColor::kBlack().withAlpha(128)); save_paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kDstOver)); + DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kDstOver)); builder.Save(); builder.ClipRect(SkRect::MakeXYWH(100, 500, 300, 300)); builder.SaveLayer(nullptr, &save_paint); @@ -277,7 +277,7 @@ TEST_P(AiksTest, TranslucentSaveLayerWithColorMatrixColorFilterDrawsCorrectly) { }; DlPaint paint; paint.setColor(DlColor::kBlack().withAlpha(128)); - paint.setColorFilter(DlMatrixColorFilter::Make(matrix)); + paint.setColorFilter(DlColorFilter::MakeMatrix(matrix)); builder.SaveLayer(nullptr, &paint); builder.DrawImage(image, SkPoint{100, 500}, {}); builder.Restore(); @@ -299,7 +299,7 @@ TEST_P(AiksTest, TranslucentSaveLayerWithColorMatrixImageFilterDrawsCorrectly) { }; DlPaint paint; paint.setColor(DlColor::kBlack().withAlpha(128)); - paint.setColorFilter(DlMatrixColorFilter::Make(matrix)); + paint.setColorFilter(DlColorFilter::MakeMatrix(matrix)); builder.SaveLayer(nullptr, &paint); builder.DrawImage(image, SkPoint{100, 500}, {}); builder.Restore(); @@ -323,9 +323,9 @@ TEST_P(AiksTest, DlPaint paint; paint.setColor(DlColor::kBlack().withAlpha(128)); paint.setImageFilter( - DlImageFilter::MakeColorFilter(DlMatrixColorFilter::Make(matrix))); + DlImageFilter::MakeColorFilter(DlColorFilter::MakeMatrix(matrix))); paint.setColorFilter( - DlBlendColorFilter::Make(DlColor::kGreen(), DlBlendMode::kModulate)); + DlColorFilter::MakeBlend(DlColor::kGreen(), DlBlendMode::kModulate)); builder.SaveLayer(nullptr, &paint); builder.DrawImage(image, SkPoint{100, 500}, {}); builder.Restore(); @@ -723,7 +723,7 @@ TEST_P(AiksTest, ImageFilteredSaveLayerWithUnboundedContents) { 0, 0, 0, 1, 0 // }; auto rgb_swap_filter = - DlImageFilter::MakeColorFilter(std::make_shared(m)); + DlImageFilter::MakeColorFilter(DlColorFilter::MakeMatrix(m)); test(rgb_swap_filter); builder.Translate(200.0, 0.0); diff --git a/impeller/display_list/canvas.cc b/impeller/display_list/canvas.cc index 7b26f02892904..11cc4d7598a9f 100644 --- a/impeller/display_list/canvas.cc +++ b/impeller/display_list/canvas.cc @@ -14,6 +14,7 @@ #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "impeller/base/validation.h" +#include "impeller/core/formats.h" #include "impeller/display_list/color_filter.h" #include "impeller/display_list/image_filter.h" #include "impeller/display_list/skia_conversions.h" @@ -36,6 +37,7 @@ #include "impeller/entity/geometry/point_field_geometry.h" #include "impeller/entity/geometry/rect_geometry.h" #include "impeller/entity/geometry/round_rect_geometry.h" +#include "impeller/entity/geometry/round_superellipse_geometry.h" #include "impeller/entity/geometry/stroke_path_geometry.h" #include "impeller/entity/save_layer_utils.h" #include "impeller/geometry/color.h" @@ -54,9 +56,7 @@ static bool UseColorSourceContents( if (vertices->HasVertexColors()) { return false; } - if (vertices->HasTextureCoordinates() && - (!paint.color_source || - paint.color_source->type() == flutter::DlColorSourceType::kColor)) { + if (vertices->HasTextureCoordinates() && !paint.color_source) { return true; } return !vertices->HasTextureCoordinates(); @@ -314,8 +314,7 @@ bool Canvas::AttemptDrawBlurredRRect(const Rect& rect, return false; } - if (paint.color_source && - paint.color_source->type() != flutter::DlColorSourceType::kColor) { + if (paint.color_source) { return false; } @@ -736,8 +735,7 @@ void Canvas::DrawVertices(const std::shared_ptr& vertices, // Override the blend mode with kDestination in order to match the behavior // of Skia's SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER flag, which // is enabled when the Flutter engine builds Skia. - if (!paint.color_source || - paint.color_source->type() == flutter::DlColorSourceType::kColor) { + if (!paint.color_source) { blend_mode = BlendMode::kDestination; } @@ -786,6 +784,7 @@ void Canvas::DrawVertices(const std::shared_ptr& vertices, contents->SetEffectTransform(effect_transform); contents->SetTexture(texture); contents->SetTileMode(x_tile_mode, y_tile_mode); + contents->SetSamplerDescriptor(sampler_descriptor); entity.SetContents(paint.WithFilters(std::move(contents))); AddRenderEntityToCurrentPass(entity); @@ -856,7 +855,7 @@ void Canvas::DrawAtlas(const std::shared_ptr& atlas_contents, void Canvas::SetupRenderPass() { renderer_.GetRenderTargetCache()->Start(); - auto color0 = render_target_.GetColorAttachments().find(0u)->second; + ColorAttachment color0 = render_target_.GetColorAttachment(0); auto& stencil_attachment = render_target_.GetStencilAttachment(); auto& depth_attachment = render_target_.GetDepthAttachment(); @@ -1463,8 +1462,7 @@ void Canvas::AddRenderEntityToCurrentPass(Entity& entity, bool reuse_depth) { RenderTarget& render_target = render_passes_.back() .inline_pass_context->GetPassTarget() .GetRenderTarget(); - ColorAttachment attachment = - render_target.GetColorAttachments().find(0u)->second; + ColorAttachment attachment = render_target.GetColorAttachment(0); // Attachment.clear color needs to be premultiplied at all times, but the // Color::Blend function requires unpremultiplied colors. attachment.clear_color = attachment.clear_color.Unpremultiply() @@ -1591,8 +1589,7 @@ std::shared_ptr Canvas::FlipBackdrop(Point global_pass_position, } if (should_use_onscreen) { - ColorAttachment color0 = - render_target_.GetColorAttachments().find(0u)->second; + ColorAttachment color0 = render_target_.GetColorAttachment(0); // When MSAA is being used, we end up overriding the entire backdrop by // drawing the previous pass texture, and so we don't have to clear it and // can use kDontCare. diff --git a/impeller/display_list/color_filter.cc b/impeller/display_list/color_filter.cc index e248ba6e09628..f5050672f3d14 100644 --- a/impeller/display_list/color_filter.cc +++ b/impeller/display_list/color_filter.cc @@ -4,7 +4,7 @@ #include "impeller/display_list/color_filter.h" -#include "display_list/effects/dl_color_filter.h" +#include "display_list/effects/dl_color_filters.h" #include "fml/logging.h" #include "impeller/display_list/skia_conversions.h" #include "impeller/entity/contents/filters/color_filter_contents.h" diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 1bdad62aff584..3fb650d36a29d 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -222,11 +222,7 @@ void DlDispatcherBase::setStrokeJoin(flutter::DlStrokeJoin join) { void DlDispatcherBase::setColorSource(const flutter::DlColorSource* source) { AUTO_DEPTH_WATCHER(0u); - if (!source || source->type() == flutter::DlColorSourceType::kColor) { - paint_.color_source = nullptr; - } else { - paint_.color_source = source; - } + paint_.color_source = source; } // |flutter::DlOpReceiver| @@ -1109,8 +1105,9 @@ void FirstPassDispatcher::drawTextFrame( // we do not double-apply the alpha. properties.color = paint_.color.WithAlpha(1.0); } - auto scale = - (matrix_ * Matrix::MakeTranslation(Point(x, y))).GetMaxBasisLengthXY(); + auto scale = TextFrame::RoundScaledFontSize( + (matrix_ * Matrix::MakeTranslation(Point(x, y))).GetMaxBasisLengthXY()); + renderer_.GetLazyGlyphAtlas()->AddTextFrame( text_frame, // scale, // diff --git a/impeller/display_list/dl_unittests.cc b/impeller/display_list/dl_unittests.cc index 06bb71d7563b3..832515a720582 100644 --- a/impeller/display_list/dl_unittests.cc +++ b/impeller/display_list/dl_unittests.cc @@ -522,18 +522,18 @@ TEST_P(DisplayListTest, CanDrawWithBlendColorFilter) { // Pipeline blended image. { - auto filter = flutter::DlBlendColorFilter(flutter::DlColor::kYellow(), - flutter::DlBlendMode::kModulate); - paint.setColorFilter(&filter); + auto filter = flutter::DlColorFilter::MakeBlend( + flutter::DlColor::kYellow(), flutter::DlBlendMode::kModulate); + paint.setColorFilter(filter); builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100), flutter::DlImageSampling::kNearestNeighbor, &paint); } // Advanced blended image. { - auto filter = flutter::DlBlendColorFilter(flutter::DlColor::kRed(), - flutter::DlBlendMode::kScreen); - paint.setColorFilter(&filter); + auto filter = flutter::DlColorFilter::MakeBlend( + flutter::DlColor::kRed(), flutter::DlBlendMode::kScreen); + paint.setColorFilter(filter); builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(250, 250), flutter::DlImageSampling::kNearestNeighbor, &paint); } @@ -552,17 +552,15 @@ TEST_P(DisplayListTest, CanDrawWithColorFilterImageFilter) { flutter::DisplayListBuilder builder; flutter::DlPaint paint; - auto color_filter = - std::make_shared(invert_color_matrix); - auto image_filter = - std::make_shared(color_filter); + auto color_filter = flutter::DlColorFilter::MakeMatrix(invert_color_matrix); + auto image_filter = flutter::DlImageFilter::MakeColorFilter(color_filter); - paint.setImageFilter(image_filter.get()); + paint.setImageFilter(image_filter); builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100), flutter::DlImageSampling::kNearestNeighbor, &paint); builder.Translate(0, 700); - paint.setColorFilter(color_filter.get()); + paint.setColorFilter(color_filter); builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100), flutter::DlImageSampling::kNearestNeighbor, &paint); ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); @@ -628,13 +626,11 @@ TEST_P(DisplayListTest, CanClampTheResultingColorOfColorMatrixFilter) { 0, 0, 0, 0.5, 0, // }; auto inner_color_filter = - std::make_shared(inner_color_matrix); + flutter::DlColorFilter::MakeMatrix(inner_color_matrix); auto outer_color_filter = - std::make_shared(outer_color_matrix); - auto inner = - std::make_shared(inner_color_filter); - auto outer = - std::make_shared(outer_color_filter); + flutter::DlColorFilter::MakeMatrix(outer_color_matrix); + auto inner = flutter::DlImageFilter::MakeColorFilter(inner_color_filter); + auto outer = flutter::DlImageFilter::MakeColorFilter(outer_color_filter); auto compose = std::make_shared(outer, inner); flutter::DisplayListBuilder builder; @@ -1109,13 +1105,11 @@ TEST_P(DisplayListTest, CanDrawRectWithLinearToSrgbColorFilter) { flutter::DlPaint paint; paint.setColor(flutter::DlColor(0xFF2196F3).withAlpha(128)); flutter::DisplayListBuilder builder; - paint.setColorFilter( - flutter::DlLinearToSrgbGammaColorFilter::kInstance.get()); + paint.setColorFilter(flutter::DlColorFilter::MakeLinearToSrgbGamma()); builder.DrawRect(SkRect::MakeXYWH(0, 0, 200, 200), paint); builder.Translate(0, 200); - paint.setColorFilter( - flutter::DlSrgbToLinearGammaColorFilter::kInstance.get()); + paint.setColorFilter(flutter::DlColorFilter::MakeSrgbToLinearGamma()); builder.DrawRect(SkRect::MakeXYWH(0, 0, 200, 200), paint); ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); @@ -1239,11 +1233,11 @@ TEST_P(DisplayListTest, CanDrawCorrectlyWithColorFilterAndImageFilter) { 0, 0, 0, 1, 0, // }; auto green_color_filter = - std::make_shared(green_color_matrix); + flutter::DlColorFilter::MakeMatrix(green_color_matrix); auto blue_color_filter = - std::make_shared(blue_color_matrix); + flutter::DlColorFilter::MakeMatrix(blue_color_matrix); auto blue_image_filter = - std::make_shared(blue_color_filter); + flutter::DlImageFilter::MakeColorFilter(blue_color_filter); flutter::DlPaint paint; paint.setColor(flutter::DlColor::kRed()); @@ -1262,30 +1256,41 @@ TEST_P(DisplayListTest, MaskBlursApplyCorrectlyToColorSources) { std::array colors = {flutter::DlColor::kBlue(), flutter::DlColor::kGreen()}; std::array stops = {0, 1}; + auto texture = CreateTextureForFixture("airplane.jpg"); + auto matrix = flutter::DlMatrix::MakeTranslation({-300, -110}); std::array, 2> color_sources = { - flutter::DlColorSource::MakeColor(flutter::DlColor::kWhite()), + flutter::DlColorSource::MakeImage( + DlImageImpeller::Make(texture), flutter::DlTileMode::kRepeat, + flutter::DlTileMode::kRepeat, flutter::DlImageSampling::kLinear, + &matrix), flutter::DlColorSource::MakeLinear( flutter::DlPoint(0, 0), flutter::DlPoint(100, 50), 2, colors.data(), - stops.data(), flutter::DlTileMode::kClamp)}; + stops.data(), flutter::DlTileMode::kClamp), + }; - int offset = 100; + builder.Save(); + builder.Translate(0, 100); for (const auto& color_source : color_sources) { flutter::DlPaint paint; paint.setColorSource(color_source); paint.setMaskFilter(blur_filter); + builder.Save(); + builder.Translate(100, 0); paint.setDrawStyle(flutter::DlDrawStyle::kFill); - builder.DrawRRect( - SkRRect::MakeRectXY(SkRect::MakeXYWH(100, offset, 100, 50), 30, 30), - paint); + builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeWH(100, 50), 30, 30), + paint); + paint.setDrawStyle(flutter::DlDrawStyle::kStroke); paint.setStrokeWidth(10); - builder.DrawRRect( - SkRRect::MakeRectXY(SkRect::MakeXYWH(300, offset, 100, 50), 30, 30), - paint); + builder.Translate(200, 0); + builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeWH(100, 50), 30, 30), + paint); - offset += 100; + builder.Restore(); + builder.Translate(0, 100); } + builder.Restore(); ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } diff --git a/impeller/display_list/paint.cc b/impeller/display_list/paint.cc index 6bbdc1a6940cb..0305a4a88e853 100644 --- a/impeller/display_list/paint.cc +++ b/impeller/display_list/paint.cc @@ -239,11 +239,6 @@ std::shared_ptr Paint::CreateContents() const { contents->SetTextureInputs(std::move(texture_inputs)); return contents; } - case flutter::DlColorSourceType::kColor: { - auto contents = std::make_shared(); - contents->SetColor(color); - return contents; - } } FML_UNREACHABLE(); } diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 48bcb2bc33075..735081d4f8db5 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -199,6 +199,8 @@ impeller_component("entity") { "geometry/rect_geometry.h", "geometry/round_rect_geometry.cc", "geometry/round_rect_geometry.h", + "geometry/round_superellipse_geometry.cc", + "geometry/round_superellipse_geometry.h", "geometry/stroke_path_geometry.cc", "geometry/stroke_path_geometry.h", "geometry/superellipse_geometry.cc", @@ -229,8 +231,6 @@ impeller_component("entity_test_helpers") { testonly = true sources = [ - "contents/test/contents_test_helpers.cc", - "contents/test/contents_test_helpers.h", "contents/test/recording_render_pass.cc", "contents/test/recording_render_pass.h", ] diff --git a/impeller/entity/contents/runtime_effect_contents.cc b/impeller/entity/contents/runtime_effect_contents.cc index e099df6f0530e..d568567277044 100644 --- a/impeller/entity/contents/runtime_effect_contents.cc +++ b/impeller/entity/contents/runtime_effect_contents.cc @@ -24,6 +24,38 @@ namespace impeller { +namespace { +constexpr char kPaddingType = 0; +constexpr char kFloatType = 1; +} // namespace + +// static +BufferView RuntimeEffectContents::EmplaceVulkanUniform( + const std::shared_ptr>& input_data, + HostBuffer& host_buffer, + const RuntimeUniformDescription& uniform) { + // TODO(jonahwilliams): rewrite this to emplace directly into + // HostBuffer. + std::vector uniform_buffer; + uniform_buffer.reserve(uniform.struct_layout.size()); + size_t uniform_byte_index = 0u; + for (char byte_type : uniform.struct_layout) { + if (byte_type == kPaddingType) { + uniform_buffer.push_back(0.f); + } else { + FML_DCHECK(byte_type == kFloatType); + uniform_buffer.push_back(reinterpret_cast( + input_data->data())[uniform_byte_index++]); + } + } + size_t alignment = std::max(sizeof(float) * uniform_buffer.size(), + DefaultUniformAlignment()); + + return host_buffer.Emplace( + reinterpret_cast(uniform_buffer.data()), + sizeof(float) * uniform_buffer.size(), alignment); +} + void RuntimeEffectContents::SetRuntimeStage( std::shared_ptr runtime_stage) { runtime_stage_ = std::move(runtime_stage); @@ -50,9 +82,9 @@ static ShaderType GetShaderType(RuntimeUniformType type) { } } -static std::shared_ptr MakeShaderMetadata( +static std::unique_ptr MakeShaderMetadata( const RuntimeUniformDescription& uniform) { - auto metadata = std::make_shared(); + std::unique_ptr metadata = std::make_unique(); metadata->name = uniform.name; metadata->members.emplace_back(ShaderStructMemberMetadata{ .type = GetShaderType(uniform.type), @@ -206,7 +238,7 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, size_t buffer_offset = 0; for (const auto& uniform : runtime_stage_->GetUniforms()) { - std::shared_ptr metadata = MakeShaderMetadata(uniform); + std::unique_ptr metadata = MakeShaderMetadata(uniform); switch (uniform.type) { case kSampledImage: { // Sampler uniforms are ordered in the IPLR according to their @@ -237,9 +269,9 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, ShaderUniformSlot uniform_slot; uniform_slot.name = uniform.name.c_str(); uniform_slot.ext_res_0 = uniform.location; - pass.BindResource(ShaderStage::kFragment, - DescriptorType::kUniformBuffer, uniform_slot, - metadata, std::move(buffer_view)); + pass.BindDynamicResource(ShaderStage::kFragment, + DescriptorType::kUniformBuffer, uniform_slot, + std::move(metadata), std::move(buffer_view)); buffer_index++; buffer_offset += uniform.GetSize(); break; @@ -251,37 +283,18 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, uniform_slot.binding = uniform.location; uniform_slot.name = uniform.name.c_str(); - // TODO(jonahwilliams): rewrite this to emplace directly into - // HostBuffer. - std::vector uniform_buffer; - uniform_buffer.reserve(uniform.struct_layout.size()); - size_t uniform_byte_index = 0u; - for (const auto& byte_type : uniform.struct_layout) { - if (byte_type == 0) { - uniform_buffer.push_back(0.f); - } else if (byte_type == 1) { - uniform_buffer.push_back(reinterpret_cast( - uniform_data_->data())[uniform_byte_index++]); - } else { - FML_UNREACHABLE(); - } - } - size_t alignment = std::max(sizeof(float) * uniform_buffer.size(), - DefaultUniformAlignment()); - - BufferView buffer_view = renderer.GetTransientsBuffer().Emplace( - reinterpret_cast(uniform_buffer.data()), - sizeof(float) * uniform_buffer.size(), alignment); - pass.BindResource(ShaderStage::kFragment, - DescriptorType::kUniformBuffer, uniform_slot, - ShaderMetadata{}, std::move(buffer_view)); + pass.BindResource( + ShaderStage::kFragment, DescriptorType::kUniformBuffer, + uniform_slot, nullptr, + EmplaceVulkanUniform(uniform_data_, + renderer.GetTransientsBuffer(), uniform)); } } } size_t sampler_index = 0; for (const auto& uniform : runtime_stage_->GetUniforms()) { - std::shared_ptr metadata = MakeShaderMetadata(uniform); + std::unique_ptr metadata = MakeShaderMetadata(uniform); switch (uniform.type) { case kSampledImage: { @@ -296,9 +309,9 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, image_slot.name = uniform.name.c_str(); image_slot.binding = uniform.binding; image_slot.texture_index = uniform.location - minimum_sampler_index; - pass.BindResource(ShaderStage::kFragment, - DescriptorType::kSampledImage, image_slot, - *metadata, input.texture, sampler); + pass.BindDynamicResource(ShaderStage::kFragment, + DescriptorType::kSampledImage, image_slot, + std::move(metadata), input.texture, sampler); sampler_index++; break; diff --git a/impeller/entity/contents/runtime_effect_contents.h b/impeller/entity/contents/runtime_effect_contents.h index 151bb315f9ef2..dd62059f221fc 100644 --- a/impeller/entity/contents/runtime_effect_contents.h +++ b/impeller/entity/contents/runtime_effect_contents.h @@ -8,6 +8,7 @@ #include #include +#include "impeller/core/host_buffer.h" #include "impeller/core/sampler_descriptor.h" #include "impeller/entity/contents/color_source_contents.h" #include "impeller/runtime_stage/runtime_stage.h" @@ -35,6 +36,12 @@ class RuntimeEffectContents final : public ColorSourceContents { /// Load the runtime effect and ensure a default PSO is initialized. bool BootstrapShader(const ContentContext& renderer) const; + // Visible for testing + static BufferView EmplaceVulkanUniform( + const std::shared_ptr>& input_data, + HostBuffer& host_buffer, + const RuntimeUniformDescription& uniform); + private: bool RegisterShader(const ContentContext& renderer) const; diff --git a/impeller/entity/contents/test/contents_test_helpers.cc b/impeller/entity/contents/test/contents_test_helpers.cc deleted file mode 100644 index fe06724eaa870..0000000000000 --- a/impeller/entity/contents/test/contents_test_helpers.cc +++ /dev/null @@ -1,11 +0,0 @@ -// 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 "impeller/entity/contents/test/contents_test_helpers.h" - -namespace impeller::testing { - -// - -} // namespace impeller::testing diff --git a/impeller/entity/contents/test/contents_test_helpers.h b/impeller/entity/contents/test/contents_test_helpers.h deleted file mode 100644 index 3783e86568c23..0000000000000 --- a/impeller/entity/contents/test/contents_test_helpers.h +++ /dev/null @@ -1,49 +0,0 @@ -// 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_IMPELLER_ENTITY_CONTENTS_TEST_CONTENTS_TEST_HELPERS_H_ -#define FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_CONTENTS_TEST_HELPERS_H_ - -#include "impeller/renderer/command.h" - -namespace impeller::testing { - -/// @brief Retrieve the [VertInfo] struct data from the provided [command]. -template -typename T::VertInfo* GetVertInfo(const Command& command) { - auto resource = std::find_if(command.vertex_bindings.buffers.begin(), - command.vertex_bindings.buffers.end(), - [](const BufferAndUniformSlot& data) { - return data.slot.ext_res_0 == 0u; - }); - if (resource == command.vertex_bindings.buffers.end()) { - return nullptr; - } - - auto data = (resource->view.resource.buffer->OnGetContents() + - resource->view.resource.range.offset); - return reinterpret_cast(data); -} - -/// @brief Retrieve the [FragInfo] struct data from the provided [command]. -template -typename T::FragInfo* GetFragInfo(const Command& command) { - auto resource = std::find_if(command.fragment_bindings.buffers.begin(), - command.fragment_bindings.buffers.end(), - [](const BufferAndUniformSlot& data) { - return data.slot.ext_res_0 == 0u || - data.slot.binding == 64; - }); - if (resource == command.fragment_bindings.buffers.end()) { - return nullptr; - } - - auto data = (resource->view.resource.buffer->OnGetContents() + - resource->view.resource.range.offset); - return reinterpret_cast(data); -} - -} // namespace impeller::testing - -#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_CONTENTS_TEST_HELPERS_H_ diff --git a/impeller/entity/contents/test/recording_render_pass.cc b/impeller/entity/contents/test/recording_render_pass.cc index 1eedfdb48d7e2..39a8f69b50c58 100644 --- a/impeller/entity/contents/test/recording_render_pass.cc +++ b/impeller/entity/contents/test/recording_render_pass.cc @@ -74,7 +74,6 @@ void RecordingRenderPass::SetInstanceCount(size_t count) { // |RenderPass| bool RecordingRenderPass::SetVertexBuffer(VertexBuffer buffer) { - pending_.BindVertices(buffer); if (delegate_) { return delegate_->SetVertexBuffer(buffer); } @@ -108,9 +107,8 @@ bool RecordingRenderPass::OnEncodeCommands(const Context& context) const { bool RecordingRenderPass::BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) { - pending_.BindResource(stage, type, slot, metadata, view); if (delegate_) { return delegate_->BindResource(stage, type, slot, metadata, view); } @@ -118,28 +116,41 @@ bool RecordingRenderPass::BindResource(ShaderStage stage, } // |RenderPass| -bool RecordingRenderPass::BindResource( +bool RecordingRenderPass::BindDynamicResource( ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, + std::unique_ptr metadata, BufferView view) { - pending_.BindResource(stage, type, slot, metadata, view); if (delegate_) { - return delegate_->BindResource(stage, type, slot, metadata, view); + return delegate_->BindDynamicResource(stage, type, slot, + std::move(metadata), view); } return true; } // |RenderPass| +bool RecordingRenderPass::BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) { + if (delegate_) { + return delegate_->BindDynamicResource( + stage, type, slot, std::move(metadata), texture, sampler); + } + return true; +} + bool RecordingRenderPass::BindResource( ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { - pending_.BindResource(stage, type, slot, metadata, texture, sampler); if (delegate_) { return delegate_->BindResource(stage, type, slot, metadata, texture, sampler); diff --git a/impeller/entity/contents/test/recording_render_pass.h b/impeller/entity/contents/test/recording_render_pass.h index 13ee9090a34b3..3fb9b34d344e1 100644 --- a/impeller/entity/contents/test/recording_render_pass.h +++ b/impeller/entity/contents/test/recording_render_pass.h @@ -46,28 +46,35 @@ class RecordingRenderPass : public RenderPass { // |RenderPass| fml::Status Draw() override; - // |RenderPass| - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) override; - - // |RenderPass| bool BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, + const ShaderMetadata* metadata, BufferView view) override; - // |RenderPass| bool BindResource(ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) override; + // |RenderPass| + bool BindDynamicResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + std::unique_ptr metadata, + BufferView view) override; + + // |RenderPass| + bool BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) override; + // |RenderPass| void OnSetLabel(std::string_view label) override; diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index dfa4c42198a94..4d4a130480157 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -175,8 +175,7 @@ bool TextContents::Render(const ContentContext& renderer, size_t bounds_offset = 0u; for (const TextRun& run : frame_->GetRuns()) { const Font& font = run.GetFont(); - Scalar rounded_scale = TextFrame::RoundScaledFontSize( - scale_, font.GetMetrics().point_size); + Scalar rounded_scale = TextFrame::RoundScaledFontSize(scale_); FontGlyphAtlas* font_atlas = nullptr; // Adjust glyph position based on the subpixel rounding @@ -220,9 +219,9 @@ bool TextContents::Render(const ContentContext& renderer, VALIDATION_LOG << "Could not find font in the atlas."; continue; } - // Note: uses unrounded scale for more accurate subpixel position. Point subpixel = TextFrame::ComputeSubpixelPosition( - glyph_position, font.GetAxisAlignment(), offset_, scale_); + glyph_position, font.GetAxisAlignment(), offset_, + rounded_scale); std::optional maybe_atlas_glyph_bounds = font_atlas->FindGlyphBounds(SubpixelGlyph{ diff --git a/impeller/entity/entity_pass_target.cc b/impeller/entity/entity_pass_target.cc index e9284de522675..db9c917b27add 100644 --- a/impeller/entity/entity_pass_target.cc +++ b/impeller/entity/entity_pass_target.cc @@ -19,7 +19,7 @@ EntityPassTarget::EntityPassTarget(const RenderTarget& render_target, std::shared_ptr EntityPassTarget::Flip( const ContentContext& renderer) { - auto color0 = target_.GetColorAttachments().find(0)->second; + ColorAttachment color0 = target_.GetColorAttachment(0); if (!color0.resolve_texture) { VALIDATION_LOG << "EntityPassTarget Flip should never be called for a " "non-MSAA target."; diff --git a/impeller/entity/entity_pass_target_unittests.cc b/impeller/entity/entity_pass_target_unittests.cc index cd22acbffdb5a..4a72138a70e19 100644 --- a/impeller/entity/entity_pass_target_unittests.cc +++ b/impeller/entity/entity_pass_target_unittests.cc @@ -31,20 +31,14 @@ TEST_P(EntityPassTargetTest, SwapWithMSAATexture) { auto entity_pass_target = EntityPassTarget(render_target, false, false); - auto color0 = entity_pass_target.GetRenderTarget() - .GetColorAttachments() - .find(0u) - ->second; + auto color0 = entity_pass_target.GetRenderTarget().GetColorAttachment(0); auto msaa_tex = color0.texture; auto resolve_tex = color0.resolve_texture; FML_DCHECK(content_context); entity_pass_target.Flip(*content_context); - color0 = entity_pass_target.GetRenderTarget() - .GetColorAttachments() - .find(0u) - ->second; + color0 = entity_pass_target.GetRenderTarget().GetColorAttachment(0); ASSERT_EQ(msaa_tex, color0.texture); ASSERT_NE(resolve_tex, color0.resolve_texture); @@ -89,10 +83,7 @@ TEST_P(EntityPassTargetTest, SwapWithMSAAImplicitResolve) { auto entity_pass_target = EntityPassTarget(render_target, false, true); - auto color0 = entity_pass_target.GetRenderTarget() - .GetColorAttachments() - .find(0u) - ->second; + auto color0 = entity_pass_target.GetRenderTarget().GetColorAttachment(0); auto msaa_tex = color0.texture; auto resolve_tex = color0.resolve_texture; @@ -101,10 +92,7 @@ TEST_P(EntityPassTargetTest, SwapWithMSAAImplicitResolve) { FML_DCHECK(content_context); entity_pass_target.Flip(*content_context); - color0 = entity_pass_target.GetRenderTarget() - .GetColorAttachments() - .find(0u) - ->second; + color0 = entity_pass_target.GetRenderTarget().GetColorAttachment(0); ASSERT_NE(msaa_tex, color0.texture); ASSERT_NE(resolve_tex, color0.resolve_texture); diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 8fee465fabe9c..ed4af453c0c32 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -37,6 +37,7 @@ #include "impeller/entity/entity_playground.h" #include "impeller/entity/geometry/geometry.h" #include "impeller/entity/geometry/point_field_geometry.h" +#include "impeller/entity/geometry/round_superellipse_geometry.h" #include "impeller/entity/geometry/stroke_path_geometry.h" #include "impeller/entity/geometry/superellipse_geometry.h" #include "impeller/geometry/color.h" @@ -1843,27 +1844,16 @@ TEST_P(EntityTest, RuntimeEffectSetsRightSizeWhenUniformIsStruct) { auto uniform_data = std::make_shared>(); uniform_data->resize(sizeof(FragUniforms)); memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms)); - contents->SetUniformData(uniform_data); - - Entity entity; - entity.SetContents(contents); - auto context = GetContentContext(); - RenderTarget target = context->GetRenderTargetCache()->CreateOffscreen( - *context->GetContext(), {1, 1}, 1u); + auto buffer_view = RuntimeEffectContents::EmplaceVulkanUniform( + uniform_data, GetContentContext()->GetTransientsBuffer(), + runtime_stage->GetUniforms()[0]); - testing::MockRenderPass pass(GetContext(), target); - ASSERT_TRUE(contents->Render(*context, entity, pass)); - ASSERT_EQ(pass.GetCommands().size(), 1u); - const auto& command = pass.GetCommands()[0]; - ASSERT_EQ(command.fragment_bindings.buffers.size(), 1u); // 16 bytes: // 8 bytes for iResolution // 4 bytes for iTime // 4 bytes padding - EXPECT_EQ( - command.fragment_bindings.buffers[0].view.resource.GetRange().length, - 16u); + EXPECT_EQ(buffer_view.GetRange().length, 16u); } TEST_P(EntityTest, ColorFilterWithForegroundColorAdvancedBlend) { @@ -2120,11 +2110,11 @@ TEST_P(EntityTest, ColorFilterContentsWithLargeGeometry) { } TEST_P(EntityTest, TextContentsCeilsGlyphScaleToDecimal) { - ASSERT_EQ(TextFrame::RoundScaledFontSize(0.4321111f, 12), 0.43f); - ASSERT_EQ(TextFrame::RoundScaledFontSize(0.5321111f, 12), 0.53f); - ASSERT_EQ(TextFrame::RoundScaledFontSize(2.1f, 12), 2.1f); - ASSERT_EQ(TextFrame::RoundScaledFontSize(0.0f, 12), 0.0f); - ASSERT_EQ(TextFrame::RoundScaledFontSize(100000000.0f, 12), 48.0f); + ASSERT_EQ(TextFrame::RoundScaledFontSize(0.4321111f), 0.43f); + ASSERT_EQ(TextFrame::RoundScaledFontSize(0.5321111f), 0.53f); + ASSERT_EQ(TextFrame::RoundScaledFontSize(2.1f), 2.1f); + ASSERT_EQ(TextFrame::RoundScaledFontSize(0.0f), 0.0f); + ASSERT_EQ(TextFrame::RoundScaledFontSize(100000000.0f), 48.0f); } TEST_P(EntityTest, SpecializationConstantsAreAppliedToVariants) { @@ -2332,6 +2322,41 @@ TEST_P(EntityTest, DrawSuperEllipse) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(EntityTest, DrawRoundSuperEllipse) { + auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { + // UI state. + static float center_x = 100; + static float center_y = 100; + static float width = 900; + static float height = 900; + static float corner_radius = 300; + static Color color = Color::Red(); + + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::SliderFloat("Center X", ¢er_x, 0, 1000); + ImGui::SliderFloat("Center Y", ¢er_y, 0, 1000); + ImGui::SliderFloat("Width", &width, 0, 1000); + ImGui::SliderFloat("Height", &height, 0, 1000); + ImGui::SliderFloat("Corner radius", &corner_radius, 0, 500); + ImGui::End(); + + auto contents = std::make_shared(); + std::unique_ptr geom = + std::make_unique( + Rect::MakeOriginSize({center_x, center_y}, {width, height}), + corner_radius); + contents->SetColor(color); + contents->SetGeometry(geom.get()); + + Entity entity; + entity.SetContents(contents); + + return entity.Render(context, pass); + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + TEST_P(EntityTest, SolidColorApplyColorFilter) { auto contents = SolidColorContents(); contents.SetColor(Color::CornflowerBlue().WithAlpha(0.75)); diff --git a/impeller/entity/geometry/round_superellipse_geometry.cc b/impeller/entity/geometry/round_superellipse_geometry.cc new file mode 100644 index 0000000000000..b595b169f1738 --- /dev/null +++ b/impeller/entity/geometry/round_superellipse_geometry.cc @@ -0,0 +1,429 @@ +// 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 + +#include "flutter/impeller/entity/geometry/round_superellipse_geometry.h" + +#include "impeller/geometry/constants.h" + +namespace impeller { + +namespace { +// A look up table with precomputed variables. +// +// The columns represent the following variabls respectively: +// +// * ratio = size / a +// * n +// * d / a +// * thetaJ +// +// For definition of the variables, see DrawOctantSquareLikeSquircle. +constexpr Scalar kPrecomputedVariables[][4] = { + {2.000, 2.00000, 0.00000, 0.24040}, // + {2.020, 2.03340, 0.01447, 0.24040}, // + {2.040, 2.06540, 0.02575, 0.21167}, // + {2.060, 2.09800, 0.03668, 0.20118}, // + {2.080, 2.13160, 0.04719, 0.19367}, // + {2.100, 2.17840, 0.05603, 0.16233}, // + {2.120, 2.19310, 0.06816, 0.20020}, // + {2.140, 2.22990, 0.07746, 0.19131}, // + {2.160, 2.26360, 0.08693, 0.19008}, // + {2.180, 2.30540, 0.09536, 0.17935}, // + {2.200, 2.32900, 0.10541, 0.19136}, // + {2.220, 2.38330, 0.11237, 0.17130}, // + {2.240, 2.39770, 0.12271, 0.18956}, // + {2.260, 2.41770, 0.13251, 0.20254}, // + {2.280, 2.47180, 0.13879, 0.18454}, // + {2.300, 2.50910, 0.14658, 0.18261} // +}; + +constexpr size_t kNumRecords = + sizeof(kPrecomputedVariables) / sizeof(kPrecomputedVariables[0]); +constexpr Scalar kMinRatio = kPrecomputedVariables[0][0]; +constexpr Scalar kMaxRatio = kPrecomputedVariables[kNumRecords - 1][0]; +constexpr Scalar kRatioStep = + kPrecomputedVariables[1][0] - kPrecomputedVariables[0][0]; + +// Linear interpolation for `kPrecomputedVariables`. +// +// The `column` is a 0-based index that decides the target variable, where 1 +// corresponds to the 2nd element of each row, etc. +// +// The `ratio` corresponds to column 0, on which the lerp is calculated. +Scalar LerpPrecomputedVariable(size_t column, Scalar ratio) { + Scalar steps = + std::clamp((ratio - kMinRatio) / kRatioStep, 0, kNumRecords - 1); + size_t left = + std::clamp((size_t)std::floor(steps), 0, kNumRecords - 2); + Scalar frac = steps - left; + + return (1 - frac) * kPrecomputedVariables[left][column] + + frac * kPrecomputedVariables[left + 1][column]; +} + +// Return the shortest of `corner_radius`, height/2, and width/2. +// +// Corner radii longer than 1/2 of the side length does not make sense, and will +// be limited to the longest possible. +Scalar LimitRadius(Scalar corner_radius, const Rect& bounds) { + return std::min(corner_radius, + std::min(bounds.GetWidth() / 2, bounds.GetHeight() / 2)); +} + +// The max angular step that the algorithm will traverse a quadrant of the +// curve. +// +// This limits the max number of points of the curve. +constexpr Scalar kMaxQuadrantSteps = 40; + +// Calculates the angular step size for a smooth curve. +// +// Returns the angular step needed to ensure a curve appears smooth +// based on the smallest dimension of a shape. Smaller dimensions require +// larger steps as less detail is needed for smoothness. +// +// The `minDimension` is the smallest dimension (e.g., width or height) of the +// shape. +// +// The `fullAngle` is the total angular range to traverse. +Scalar CalculateStep(Scalar minDimension, Scalar fullAngle) { + constexpr Scalar kMinAngleStep = kPiOver2 / kMaxQuadrantSteps; + + // Assumes at least 1 point is needed per pixel to achieve sufficient + // smoothness. + constexpr Scalar pointsPerPixel = 1.0; + size_t pointsByDimension = (size_t)std::ceil(minDimension * pointsPerPixel); + Scalar angleByDimension = fullAngle / pointsByDimension; + + return std::min(kMinAngleStep, angleByDimension); +} + +// The distance from point M (the 45deg point) to either side of the closer +// bounding box is defined as `CalculateGap`. +constexpr Scalar CalculateGap(Scalar corner_radius) { + // Heuristic formula derived from experimentation. + return 0.2924066406 * corner_radius; +} + +// Draw a circular arc from `start` to `end` with a radius of `r`. +// +// It is assumed that `start` is north-west to `end`, and the center +// of the circle is south-west to both points. +// +// The resulting points are appended to `output` and include the starting point +// but exclude the ending point. +// +// Returns the number of the +size_t DrawCircularArc(Point* output, Point start, Point end, Scalar r) { + /* Denote the middle point of S and E as M. The key is to find the center of + * the circle. + * S --__ + * / ⟍ `、 + * / M ⟍\ + * / ⟋ E + * / ⟋ ↗ + * / ⟋ + * / ⟋ r + * C ᜱ ↙ + */ + + Point s_to_e = end - start; + Point m = (start + end) / 2; + Point c_to_m = Point(-s_to_e.y, s_to_e.x); + Scalar distance_sm = s_to_e.GetLength() / 2; + Scalar distance_cm = sqrt(r * r - distance_sm * distance_sm); + Point c = m - distance_cm * c_to_m.Normalize(); + Scalar angle_sce = asinf(distance_sm / r) * 2; + Point c_to_s = start - c; + + Scalar step = CalculateStep(std::abs(s_to_e.y), angle_sce); + + Point* next = output; + Scalar angle = 0; + while (angle < angle_sce) { + *(next++) = c_to_s.Rotate(Radians(-angle)) + c; + angle += step; + } + return next - output; +} + +// Draws an arc representing the top 1/8 segment of a square-like rounded +// superellipse. +// +// The resulting arc centers at the origin, spanning from 0 to pi/4, moving +// clockwise starting from the positive Y-axis, and includes the starting point +// (the middle of the top flat side) while excluding the ending point (the x=y +// point). +// +// The full square-like rounded superellipse has a width and height specified by +// `size` and features rounded corners determined by `corner_radius`. The +// `corner_radius` corresponds to the `cornerRadius` parameter in SwiftUI, +// rather than the literal radius of corner circles. +// +// Returns the number of points generated. +size_t DrawOctantSquareLikeSquircle(Point* output, + Scalar size, + Scalar corner_radius) { + /* The following figure shows the first quadrant of a square-like rounded + * superellipse. The target arc consists of the "stretch" (AB), a + * superellipsoid arc (BJ), and a circular arc (JM). + * + * straight superelipse + * ↓ ↓ + * A B J circular arc + * ---------...._ ↙ + * | | / `⟍ M + * | | / ⟋ ⟍ + * | | / ⟋ \ + * | | / ⟋ | + * | | ᜱD | + * | | / | + * ↑ +----+ | + * s | | | + * ↓ +----+---------------| A' + * O S + * ← s → + * ←------ size/2 ------→ + * + * Define gap (g) as the distance between point M and the bounding box, + * therefore point M is at (size/2 - g, size/2 - g). + * + * The superellipsoid curve can be drawn with an implicit parameter θ: + * x = a * sinθ ^ (2/n) + * y = a * cosθ ^ (2/n) + * https://math.stackexchange.com/questions/2573746/superellipse-parametric-equation + * + * Define thetaJ as the θ at point J. + */ + + Scalar ratio = {std::min(size / corner_radius, kMaxRatio)}; + Scalar a = ratio * corner_radius / 2; + Scalar s = size / 2 - a; + Scalar g = CalculateGap(corner_radius); + + Scalar n = LerpPrecomputedVariable(1, ratio); + Scalar d = LerpPrecomputedVariable(2, ratio) * a; + Scalar thetaJ = LerpPrecomputedVariable(3, ratio); + + Scalar R = (a - d - g) * sqrt(2); + + Point pointM(size / 2 - g, size / 2 - g); + + Scalar xJ = a * pow(abs(sinf(thetaJ)), 2 / n); + Scalar yJ = a * pow(abs(cosf(thetaJ)), 2 / n); + + Point* next = output; + // A + *(next++) = Point(0, size / 2); + // Superellipsoid arc BJ (B inclusive, J exclusive) + { + Scalar step = CalculateStep(a - yJ, thetaJ); + Scalar angle = 0; + while (angle < thetaJ) { + Scalar x = a * pow(abs(sinf(angle)), 2 / n); + Scalar y = a * pow(abs(cosf(angle)), 2 / n); + *(next++) = Point(x + s, y + s); + angle += step; + } + } + + // Circular arc JM (B inclusive, M exclusive) + next += DrawCircularArc(next, {xJ + s, yJ + s}, pointM, R); + return next - output; +} + +// Optionally `flip` the input points before offsetting it by `center`, and +// append the result to `output`. +// +// If `flip` is true, then the entire input list is reversed, and the x and y +// coordinate of each point is swapped as well. This effectively mirrors the +// input point list by the y=x line. +size_t FlipAndOffset(Point* output, + const Point* input, + size_t input_length, + bool flip, + const Point& center) { + if (!flip) { + for (size_t i = 0; i < input_length; i++) { + output[i] = input[i] + center; + } + } else { + for (size_t i = 0; i < input_length; i++) { + const Point& point = input[input_length - i - 1]; + output[i] = Point(point.y + center.x, point.x + center.y); + } + } + return input_length; +} + +constexpr Point kReflection[4] = {{1, 1}, {1, -1}, {-1, -1}, {-1, 1}}; + +// Mirror the point list `quad` into other quadrants and output as a triangle +// strip. +// +// The input arc `quad` should reside in the first quadrant, starting at +// positive Y axis and ending at positive X axis (both ends inclusive), for a +// total of `quad_length` points. This function mirrors the arc into 4 +// quadrants, offset the result by `center`, and rearrange it as a triangle +// strip, which is appended to `output`. +// +// A total of (quad_length - 1) * 4 points will be appended, and `output` must +// have sufficient memory allocated before this call. +void MirrorIntoTriangleStrip(const Point* quad, + size_t quad_length, + const Point& center, + Point* output) { + // The length of 1/4 arc including the starting point but excluding the + // ending point. + const size_t arc_length = quad_length - 1; + auto GetPoint = [quad, arc_length](size_t i) -> Point { + if (i < arc_length) { + return quad[i]; + } + i = i - arc_length; + if (i < arc_length) { + return quad[arc_length - i] * kReflection[1]; + } + i = i - arc_length; + if (i < arc_length) { + return quad[i] * kReflection[2]; + } + i = i - arc_length; + if (i < arc_length) { + return quad[arc_length - i] * kReflection[3]; + } else { + // Unreachable + return Point(); + } + }; + + size_t index_count = 0; + + output[index_count++] = GetPoint(0) + center; + + size_t a = 1; + size_t b = arc_length * 4 - 1; + while (a < b) { + output[index_count++] = GetPoint(a) + center; + output[index_count++] = GetPoint(b) + center; + a++; + b--; + } + if (a == b) { + output[index_count++] = GetPoint(b) + center; + } +} + +} // namespace + +RoundSuperellipseGeometry::RoundSuperellipseGeometry(const Rect& bounds, + Scalar corner_radius) + : bounds_(bounds), corner_radius_(LimitRadius(corner_radius, bounds)) {} + +RoundSuperellipseGeometry::~RoundSuperellipseGeometry() {} + +GeometryResult RoundSuperellipseGeometry::GetPositionBuffer( + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + const Size size = bounds_.GetSize(); + const Point center = bounds_.GetCenter(); + + // The full shape is divided into 4 segments: the top and bottom edges come + // from two square-like rounded superellipses (called "width-aligned"), while + // the left and right squircles come from another two ("height-aligned"). + // + // Denote the distance from the center of the square-like squircles to the + // origin as `c`. The width-aligned square-like squircle and the + // height-aligned one have the same offset in different directions. + const Scalar c = (size.width - size.height) / 2; + + // The cache is allocated as follows: + // + // * The first chunk stores the quadrant arc. + // * The second chunk stores an octant arc before flipping and translation. + Point* cache = renderer.GetTessellator().GetStrokePointCache().data(); + + // The memory size (in units of Points) allocated to store the first chunk. + constexpr size_t kMaxQuadrantLength = kPointArenaSize / 4; + // Since the curve is traversed in steps bounded by kMaxQuadrantSteps, the + // curving part will have fewer points than kMaxQuadrantSteps. Multiply it by + // 2 for storing other sporatic points (an extremely conservative estimate). + static_assert(kMaxQuadrantLength > 2 * kMaxQuadrantSteps); + + // Draw the first quadrant of the shape and store in `quadrant`, including + // both ends. It will be mirrored to other quadrants later. + Point* quadrant = cache; + size_t quadrant_length; + { + Point* next = quadrant; + + Point* octant_cache = cache + kMaxQuadrantLength; + size_t octant_length; + + octant_length = + DrawOctantSquareLikeSquircle(octant_cache, size.width, corner_radius_); + next += FlipAndOffset(next, octant_cache, octant_length, /*flip=*/false, + Point(0, -c)); + + *(next++) = Point(size / 2) - CalculateGap(corner_radius_); // Point M + + octant_length = + DrawOctantSquareLikeSquircle(octant_cache, size.height, corner_radius_); + next += FlipAndOffset(next, octant_cache, octant_length, /*flip=*/true, + Point(c, 0)); + + quadrant_length = next - quadrant; + } + + // The `contour_point_count` include all points on the border. The "-1" comes + // from duplicate ends from the mirrored arcs. + size_t contour_length = 4 * (quadrant_length - 1); + BufferView vertex_buffer = renderer.GetTransientsBuffer().Emplace( + nullptr, sizeof(Point) * contour_length, alignof(Point)); + Point* vertex_data = + reinterpret_cast(vertex_buffer.GetBuffer()->OnGetContents() + + vertex_buffer.GetRange().offset); + + MirrorIntoTriangleStrip(quadrant, quadrant_length, center, vertex_data); + + return GeometryResult{ + .type = PrimitiveType::kTriangleStrip, + .vertex_buffer = + { + .vertex_buffer = vertex_buffer, + .vertex_count = contour_length, + .index_type = IndexType::kNone, + }, + .transform = entity.GetShaderTransform(pass), + }; +} + +std::optional RoundSuperellipseGeometry::GetCoverage( + const Matrix& transform) const { + return bounds_.TransformBounds(transform); +} + +bool RoundSuperellipseGeometry::CoversArea(const Matrix& transform, + const Rect& rect) const { + if (!transform.IsTranslationScaleOnly()) { + return false; + } + // Use the rectangle formed by the four 45deg points (point M) as a + // conservative estimate of the inner rectangle. + Scalar g = CalculateGap(corner_radius_); + Rect coverage = + Rect::MakeLTRB(bounds_.GetLeft() + g, bounds_.GetTop() + g, + bounds_.GetRight() - g, bounds_.GetBottom() - g) + .TransformBounds(transform); + return coverage.Contains(rect); +} + +bool RoundSuperellipseGeometry::IsAxisAlignedRect() const { + return false; +} + +} // namespace impeller diff --git a/impeller/entity/geometry/round_superellipse_geometry.h b/impeller/entity/geometry/round_superellipse_geometry.h new file mode 100644 index 0000000000000..c5d5c7bfc9965 --- /dev/null +++ b/impeller/entity/geometry/round_superellipse_geometry.h @@ -0,0 +1,58 @@ +// 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_IMPELLER_ENTITY_GEOMETRY_ROUND_SUPERELLIPSE_GEOMETRY_H_ +#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_ROUND_SUPERELLIPSE_GEOMETRY_H_ + +#include "impeller/entity/geometry/geometry.h" + +namespace impeller { + +/// Geometry class that can generate vertices for a rounded superellipse. +/// +/// A superellipse is an ellipse-like shape that is defined by the parameters N, +/// alpha, and beta: +/// +/// 1 = |x / b| ^n + |y / a| ^n +/// +/// A rounded superellipse is a square-like superellipse (a=b) with its four +/// corners replaced by circular arcs. It replicates the `RoundedRectangle` +/// shape in SwiftUI with corner style `.continuous`. +/// +/// The `bounds` defines the position and size of the shape. The `corner_radius` +/// corresponds to SwiftUI's `cornerRadius` parameter, which is close to, but +/// not exactly equals to, the radius of the corner circles. +class RoundSuperellipseGeometry final : public Geometry { + public: + explicit RoundSuperellipseGeometry(const Rect& bounds, Scalar corner_radius); + + ~RoundSuperellipseGeometry() override; + + // |Geometry| + bool CoversArea(const Matrix& transform, const Rect& rect) const override; + + // |Geometry| + bool IsAxisAlignedRect() const override; + + private: + // |Geometry| + GeometryResult GetPositionBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + // |Geometry| + std::optional GetCoverage(const Matrix& transform) const override; + + const Rect bounds_; + double corner_radius_; + + RoundSuperellipseGeometry(const RoundSuperellipseGeometry&) = delete; + + RoundSuperellipseGeometry& operator=(const RoundSuperellipseGeometry&) = + delete; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_ROUND_SUPERELLIPSE_GEOMETRY_H_ diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index ac86af2139143..82d94a614ec5d 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -86,20 +86,13 @@ const std::shared_ptr& InlinePassContext::GetRenderPass() { return pass_; } - if (pass_target_.GetRenderTarget().GetColorAttachments().empty()) { - VALIDATION_LOG << "Color attachment unexpectedly missing from the " - "EntityPass render target."; - return pass_; - } - command_buffer_->SetLabel("EntityPass Command Buffer"); { // If the pass target has a resolve texture, then we're using MSAA. - bool is_msaa = pass_target_.GetRenderTarget() - .GetColorAttachments() - .find(0) - ->second.resolve_texture != nullptr; + bool is_msaa = + pass_target_.GetRenderTarget().GetColorAttachment(0).resolve_texture != + nullptr; if (pass_count_ > 0 && is_msaa) { pass_target_.Flip(renderer_); } @@ -107,8 +100,7 @@ const std::shared_ptr& InlinePassContext::GetRenderPass() { // Find the color attachment a second time, since the target may have just // flipped. - auto color0 = - pass_target_.GetRenderTarget().GetColorAttachments().find(0)->second; + ColorAttachment color0 = pass_target_.GetRenderTarget().GetColorAttachment(0); bool is_msaa = color0.resolve_texture != nullptr; if (pass_count_ > 0) { diff --git a/impeller/entity/render_target_cache.cc b/impeller/entity/render_target_cache.cc index dbfe0a9b50c63..3bc6e20d5dfce 100644 --- a/impeller/entity/render_target_cache.cc +++ b/impeller/entity/render_target_cache.cc @@ -3,12 +3,15 @@ // found in the LICENSE file. #include "impeller/entity/render_target_cache.h" +#include "impeller/core/formats.h" #include "impeller/renderer/render_target.h" namespace impeller { -RenderTargetCache::RenderTargetCache(std::shared_ptr allocator) - : RenderTargetAllocator(std::move(allocator)) {} +RenderTargetCache::RenderTargetCache(std::shared_ptr allocator, + uint32_t keep_alive_frame_count) + : RenderTargetAllocator(std::move(allocator)), + keep_alive_frame_count_(keep_alive_frame_count) {} void RenderTargetCache::Start() { for (auto& td : render_target_data_) { @@ -19,9 +22,12 @@ void RenderTargetCache::Start() { void RenderTargetCache::End() { std::vector retain; - for (const auto& td : render_target_data_) { + for (RenderTargetData& td : render_target_data_) { if (td.used_this_frame) { retain.push_back(td); + } else if (td.keep_alive_frame_count > 0) { + td.keep_alive_frame_count--; + retain.push_back(td); } } render_target_data_.swap(retain); @@ -48,14 +54,15 @@ RenderTarget RenderTargetCache::CreateOffscreen( .has_msaa = false, .has_depth_stencil = stencil_attachment_config.has_value(), }; - for (auto& render_target_data : render_target_data_) { - const auto other_config = render_target_data.config; + for (RenderTargetData& render_target_data : render_target_data_) { + const RenderTargetConfig other_config = render_target_data.config; if (!render_target_data.used_this_frame && other_config == config) { render_target_data.used_this_frame = true; - auto color0 = render_target_data.render_target.GetColorAttachments() - .find(0u) - ->second; - auto depth = render_target_data.render_target.GetDepthAttachment(); + render_target_data.keep_alive_frame_count = keep_alive_frame_count_; + ColorAttachment color0 = + render_target_data.render_target.GetColorAttachment(0); + std::optional depth = + render_target_data.render_target.GetDepthAttachment(); std::shared_ptr depth_tex = depth ? depth->texture : nullptr; return RenderTargetAllocator::CreateOffscreen( context, size, mip_count, label, color_attachment_config, @@ -68,10 +75,12 @@ RenderTarget RenderTargetCache::CreateOffscreen( if (!created_target.IsValid()) { return created_target; } - render_target_data_.push_back( - RenderTargetData{.used_this_frame = true, - .config = config, - .render_target = created_target}); + render_target_data_.push_back(RenderTargetData{ + .used_this_frame = true, // + .keep_alive_frame_count = keep_alive_frame_count_, // + .config = config, // + .render_target = created_target // + }); return created_target; } @@ -98,14 +107,15 @@ RenderTarget RenderTargetCache::CreateOffscreenMSAA( .has_msaa = true, .has_depth_stencil = stencil_attachment_config.has_value(), }; - for (auto& render_target_data : render_target_data_) { - const auto other_config = render_target_data.config; + for (RenderTargetData& render_target_data : render_target_data_) { + const RenderTargetConfig other_config = render_target_data.config; if (!render_target_data.used_this_frame && other_config == config) { render_target_data.used_this_frame = true; - auto color0 = render_target_data.render_target.GetColorAttachments() - .find(0u) - ->second; - auto depth = render_target_data.render_target.GetDepthAttachment(); + render_target_data.keep_alive_frame_count = keep_alive_frame_count_; + ColorAttachment color0 = + render_target_data.render_target.GetColorAttachment(0); + std::optional depth = + render_target_data.render_target.GetDepthAttachment(); std::shared_ptr depth_tex = depth ? depth->texture : nullptr; return RenderTargetAllocator::CreateOffscreenMSAA( context, size, mip_count, label, color_attachment_config, @@ -119,10 +129,12 @@ RenderTarget RenderTargetCache::CreateOffscreenMSAA( if (!created_target.IsValid()) { return created_target; } - render_target_data_.push_back( - RenderTargetData{.used_this_frame = true, - .config = config, - .render_target = created_target}); + render_target_data_.push_back(RenderTargetData{ + .used_this_frame = true, // + .keep_alive_frame_count = keep_alive_frame_count_, // + .config = config, // + .render_target = created_target // + }); return created_target; } diff --git a/impeller/entity/render_target_cache.h b/impeller/entity/render_target_cache.h index 7c7f91451b7cc..c877dc422e872 100644 --- a/impeller/entity/render_target_cache.h +++ b/impeller/entity/render_target_cache.h @@ -16,7 +16,8 @@ namespace impeller { /// Any textures unused after a frame are immediately discarded. class RenderTargetCache : public RenderTargetAllocator { public: - explicit RenderTargetCache(std::shared_ptr allocator); + explicit RenderTargetCache(std::shared_ptr allocator, + uint32_t keep_alive_frame_count = 4); ~RenderTargetCache() = default; @@ -59,11 +60,13 @@ class RenderTargetCache : public RenderTargetAllocator { private: struct RenderTargetData { bool used_this_frame; + uint32_t keep_alive_frame_count; RenderTargetConfig config; RenderTarget render_target; }; std::vector render_target_data_; + uint32_t keep_alive_frame_count_; RenderTargetCache(const RenderTargetCache&) = delete; diff --git a/impeller/entity/render_target_cache_unittests.cc b/impeller/entity/render_target_cache_unittests.cc index 73493e7641c85..4fe3ffb0c9c4d 100644 --- a/impeller/entity/render_target_cache_unittests.cc +++ b/impeller/entity/render_target_cache_unittests.cc @@ -7,6 +7,7 @@ #include "flutter/testing/testing.h" #include "impeller/base/validation.h" #include "impeller/core/allocator.h" +#include "impeller/core/formats.h" #include "impeller/core/texture_descriptor.h" #include "impeller/entity/entity_playground.h" #include "impeller/entity/render_target_cache.h" @@ -49,8 +50,8 @@ class TestAllocator : public Allocator { }; TEST_P(RenderTargetCacheTest, CachesUsedTexturesAcrossFrames) { - auto render_target_cache = - RenderTargetCache(GetContext()->GetResourceAllocator()); + auto render_target_cache = RenderTargetCache( + GetContext()->GetResourceAllocator(), /*keep_alive_frame_count=*/0); render_target_cache.Start(); // Create two render targets of the same exact size/shape. Both should be @@ -72,10 +73,41 @@ TEST_P(RenderTargetCacheTest, CachesUsedTexturesAcrossFrames) { EXPECT_EQ(render_target_cache.CachedTextureCount(), 1u); } +TEST_P(RenderTargetCacheTest, CachesUsedTexturesAcrossFramesWithKeepAlive) { + auto render_target_cache = RenderTargetCache( + GetContext()->GetResourceAllocator(), /*keep_alive_frame_count=*/3); + + render_target_cache.Start(); + // Create two render targets of the same exact size/shape. Both should be + // marked as used this frame, so the cached data set will contain two. + render_target_cache.CreateOffscreen(*GetContext(), {100, 100}, 1); + render_target_cache.CreateOffscreen(*GetContext(), {100, 100}, 1); + + EXPECT_EQ(render_target_cache.CachedTextureCount(), 2u); + + render_target_cache.End(); + render_target_cache.Start(); + + // The unused texture is kept alive until the keep alive countdown + // reaches 0. + EXPECT_EQ(render_target_cache.CachedTextureCount(), 2u); + + for (auto i = 0; i < 3; i++) { + render_target_cache.Start(); + render_target_cache.End(); + EXPECT_EQ(render_target_cache.CachedTextureCount(), 2u); + } + // After the countdown has elapsed the texture is removed. + render_target_cache.Start(); + render_target_cache.End(); + EXPECT_EQ(render_target_cache.CachedTextureCount(), 0u); +} + TEST_P(RenderTargetCacheTest, DoesNotPersistFailedAllocations) { ScopedValidationDisable disable; auto allocator = std::make_shared(); - auto render_target_cache = RenderTargetCache(allocator); + auto render_target_cache = + RenderTargetCache(allocator, /*keep_alive_frame_count=*/0); render_target_cache.Start(); allocator->should_fail = true; @@ -88,8 +120,8 @@ TEST_P(RenderTargetCacheTest, DoesNotPersistFailedAllocations) { } TEST_P(RenderTargetCacheTest, CachedTextureGetsNewAttachmentConfig) { - auto render_target_cache = - RenderTargetCache(GetContext()->GetResourceAllocator()); + auto render_target_cache = RenderTargetCache( + GetContext()->GetResourceAllocator(), /*keep_alive_frame_count=*/0); render_target_cache.Start(); RenderTarget::AttachmentConfig color_attachment_config = @@ -104,8 +136,8 @@ TEST_P(RenderTargetCacheTest, CachedTextureGetsNewAttachmentConfig) { *GetContext(), {100, 100}, 1, "Offscreen2", color_attachment_config); render_target_cache.End(); - auto color1 = target1.GetColorAttachments().find(0)->second; - auto color2 = target2.GetColorAttachments().find(0)->second; + ColorAttachment color1 = target1.GetColorAttachment(0); + ColorAttachment color2 = target2.GetColorAttachment(0); // The second color attachment should reuse the first attachment's texture // but with attributes from the second AttachmentConfig. EXPECT_EQ(color2.texture, color1.texture); @@ -113,8 +145,8 @@ TEST_P(RenderTargetCacheTest, CachedTextureGetsNewAttachmentConfig) { } TEST_P(RenderTargetCacheTest, CreateWithEmptySize) { - auto render_target_cache = - RenderTargetCache(GetContext()->GetResourceAllocator()); + auto render_target_cache = RenderTargetCache( + GetContext()->GetResourceAllocator(), /*keep_alive_frame_count=*/0); render_target_cache.Start(); RenderTarget empty_target = diff --git a/impeller/entity/save_layer_utils.cc b/impeller/entity/save_layer_utils.cc index 304990240ec84..f6ad180f8cfba 100644 --- a/impeller/entity/save_layer_utils.cc +++ b/impeller/entity/save_layer_utils.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "impeller/entity/save_layer_utils.h" +#include "impeller/geometry/scalar.h" namespace impeller { @@ -11,6 +12,8 @@ bool SizeDifferenceUnderThreshold(Size a, Size b, Scalar threshold) { return (std::abs(a.width - b.width) / b.width) < threshold && (std::abs(a.height - b.height) / b.height) < threshold; } + +static constexpr Scalar kDefaultSizeThreshold = 0.3; } // namespace std::optional ComputeSaveLayerCoverage( @@ -83,7 +86,8 @@ std::optional ComputeSaveLayerCoverage( transformed_coverage.Intersection(source_coverage_limit.value()); if (intersected_coverage.has_value() && SizeDifferenceUnderThreshold(transformed_coverage.GetSize(), - intersected_coverage->GetSize(), 0.2)) { + intersected_coverage->GetSize(), + kDefaultSizeThreshold)) { // Returning the transformed coverage is always correct, it just may // be larger than the clip area or onscreen texture. return transformed_coverage; @@ -106,8 +110,22 @@ std::optional ComputeSaveLayerCoverage( // Transform the input coverage into the global coordinate space before // computing the bounds limit intersection. - return coverage.TransformBounds(effect_transform) - .Intersection(coverage_limit); + Rect transformed_coverage = coverage.TransformBounds(effect_transform); + std::optional intersection = + transformed_coverage.Intersection(coverage_limit); + if (!intersection.has_value()) { + return std::nullopt; + } + // The the resulting coverage rect is nearly the same as the coverage_limit, + // round up to the coverage_limit. + Rect intersect_rect = intersection.value(); + if (SizeDifferenceUnderThreshold(intersect_rect.GetSize(), + coverage_limit.GetSize(), + kDefaultSizeThreshold)) { + return coverage_limit; + } + + return intersect_rect; } } // namespace impeller diff --git a/impeller/entity/save_layer_utils_unittests.cc b/impeller/entity/save_layer_utils_unittests.cc index b72ac33ae768b..5139204d7c2af 100644 --- a/impeller/entity/save_layer_utils_unittests.cc +++ b/impeller/entity/save_layer_utils_unittests.cc @@ -280,6 +280,63 @@ TEST(SaveLayerUtilsTest, EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 50)); } +TEST(SaveLayerUtilsTest, RoundUpCoverageWhenCloseToCoverageLimit) { + // X varies, translation is performed on coverage. + auto coverage = ComputeSaveLayerCoverage( + /*content_coverage=*/Rect::MakeLTRB(0, 0, 90, 90), // + /*effect_transform=*/{}, // + /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), // + /*image_filter=*/nullptr // + ); + + ASSERT_TRUE(coverage.has_value()); + // Size that matches coverage limit + EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 100, 100)); +} + +TEST(SaveLayerUtilsTest, DontRoundUpCoverageWhenNotCloseToCoverageLimitWidth) { + // X varies, translation is performed on coverage. + auto coverage = ComputeSaveLayerCoverage( + /*content_coverage=*/Rect::MakeLTRB(0, 0, 50, 90), // + /*effect_transform=*/{}, // + /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), // + /*image_filter=*/nullptr // + ); + + ASSERT_TRUE(coverage.has_value()); + // Size that matches coverage limit + EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 90)); +} + +TEST(SaveLayerUtilsTest, DontRoundUpCoverageWhenNotCloseToCoverageLimitHeight) { + // X varies, translation is performed on coverage. + auto coverage = ComputeSaveLayerCoverage( + /*content_coverage=*/Rect::MakeLTRB(0, 0, 90, 50), // + /*effect_transform=*/{}, // + /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), // + /*image_filter=*/nullptr // + ); + + ASSERT_TRUE(coverage.has_value()); + // Size that matches coverage limit + EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 90, 50)); +} + +TEST(SaveLayerUtilsTest, + DontRoundUpCoverageWhenNotCloseToCoverageLimitWidthHeight) { + // X varies, translation is performed on coverage. + auto coverage = ComputeSaveLayerCoverage( + /*content_coverage=*/Rect::MakeLTRB(0, 0, 50, 50), // + /*effect_transform=*/{}, // + /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), // + /*image_filter=*/nullptr // + ); + + ASSERT_TRUE(coverage.has_value()); + // Size that matches coverage limit + EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 50)); +} + } // namespace testing } // namespace impeller diff --git a/impeller/geometry/path.h b/impeller/geometry/path.h index d81b3cb0ec6f8..86263aa9071f9 100644 --- a/impeller/geometry/path.h +++ b/impeller/geometry/path.h @@ -6,6 +6,7 @@ #define FLUTTER_IMPELLER_GEOMETRY_PATH_H_ #include +#include #include #include #include diff --git a/impeller/geometry/size.h b/impeller/geometry/size.h index b31970f1ddc2a..2c609cddade0f 100644 --- a/impeller/geometry/size.h +++ b/impeller/geometry/size.h @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index f588a54049480..1ef9f17f134d8 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -284,12 +284,7 @@ bool Playground::OpenPlaygroundHere( } buffer->SetLabel("ImGui Command Buffer"); - if (render_target.GetColorAttachments().empty()) { - VALIDATION_LOG << "render target attachments are empty."; - return false; - } - - auto color0 = render_target.GetColorAttachments().find(0)->second; + auto color0 = render_target.GetColorAttachment(0); color0.load_action = LoadAction::kLoad; if (color0.resolve_texture) { color0.texture = color0.resolve_texture; @@ -297,7 +292,6 @@ bool Playground::OpenPlaygroundHere( color0.store_action = StoreAction::kStore; } render_target.SetColorAttachment(color0, 0); - render_target.SetStencilAttachment(std::nullopt); render_target.SetDepthAttachment(std::nullopt); diff --git a/impeller/renderer/backend/gles/BUILD.gn b/impeller/renderer/backend/gles/BUILD.gn index bede7318a32a0..a28309f5fa828 100644 --- a/impeller/renderer/backend/gles/BUILD.gn +++ b/impeller/renderer/backend/gles/BUILD.gn @@ -14,6 +14,8 @@ config("gles_config") { impeller_component("gles_unittests") { testonly = true sources = [ + "buffer_bindings_gles_unittests.cc", + "device_buffer_gles_unittests.cc", "test/capabilities_unittests.cc", "test/formats_gles_unittests.cc", "test/gpu_tracer_gles_unittests.cc", @@ -26,6 +28,7 @@ impeller_component("gles_unittests") { "test/specialization_constants_unittests.cc", "test/surface_gles_unittests.cc", "test/texture_gles_unittests.cc", + "unique_handle_gles_unittests.cc", ] deps = [ ":gles", @@ -104,5 +107,6 @@ impeller_component("gles") { "../../:renderer", "../../../shader_archive", "//flutter/fml", + "//flutter/third_party/abseil-cpp/absl/container:flat_hash_map", ] } diff --git a/impeller/renderer/backend/gles/allocator_gles.cc b/impeller/renderer/backend/gles/allocator_gles.cc index cd062d8a445e3..820ec22d69163 100644 --- a/impeller/renderer/backend/gles/allocator_gles.cc +++ b/impeller/renderer/backend/gles/allocator_gles.cc @@ -13,7 +13,7 @@ namespace impeller { -AllocatorGLES::AllocatorGLES(ReactorGLES::Ref reactor) +AllocatorGLES::AllocatorGLES(std::shared_ptr reactor) : reactor_(std::move(reactor)), is_valid_(true) {} // |Allocator| diff --git a/impeller/renderer/backend/gles/allocator_gles.h b/impeller/renderer/backend/gles/allocator_gles.h index a01c39e9597a8..14728414f467e 100644 --- a/impeller/renderer/backend/gles/allocator_gles.h +++ b/impeller/renderer/backend/gles/allocator_gles.h @@ -18,10 +18,10 @@ class AllocatorGLES final : public Allocator { private: friend class ContextGLES; - ReactorGLES::Ref reactor_; + std::shared_ptr reactor_; bool is_valid_ = false; - explicit AllocatorGLES(ReactorGLES::Ref reactor); + explicit AllocatorGLES(std::shared_ptr reactor); // |Allocator| bool IsValid() const; diff --git a/impeller/renderer/backend/gles/blit_pass_gles.cc b/impeller/renderer/backend/gles/blit_pass_gles.cc index 94d830001eb98..7e8aaf9238d1f 100644 --- a/impeller/renderer/backend/gles/blit_pass_gles.cc +++ b/impeller/renderer/backend/gles/blit_pass_gles.cc @@ -14,7 +14,7 @@ namespace impeller { -BlitPassGLES::BlitPassGLES(ReactorGLES::Ref reactor) +BlitPassGLES::BlitPassGLES(std::shared_ptr reactor) : reactor_(std::move(reactor)), is_valid_(reactor_ && reactor_->IsValid()) {} diff --git a/impeller/renderer/backend/gles/blit_pass_gles.h b/impeller/renderer/backend/gles/blit_pass_gles.h index 321bd42dc9e8a..f3780f4bd41b2 100644 --- a/impeller/renderer/backend/gles/blit_pass_gles.h +++ b/impeller/renderer/backend/gles/blit_pass_gles.h @@ -25,11 +25,11 @@ class BlitPassGLES final : public BlitPass, friend class CommandBufferGLES; std::vector> commands_; - ReactorGLES::Ref reactor_; + std::shared_ptr reactor_; std::string label_; bool is_valid_ = false; - explicit BlitPassGLES(ReactorGLES::Ref reactor); + explicit BlitPassGLES(std::shared_ptr reactor); // |BlitPass| bool IsValid() const override; diff --git a/impeller/renderer/backend/gles/buffer_bindings_gles.cc b/impeller/renderer/backend/gles/buffer_bindings_gles.cc index e4adb99a9b94a..3f10bc9b5d4ea 100644 --- a/impeller/renderer/backend/gles/buffer_bindings_gles.cc +++ b/impeller/renderer/backend/gles/buffer_bindings_gles.cc @@ -8,11 +8,14 @@ #include #include "impeller/base/validation.h" +#include "impeller/core/buffer_view.h" +#include "impeller/core/device_buffer.h" #include "impeller/core/shader_types.h" #include "impeller/renderer/backend/gles/device_buffer_gles.h" #include "impeller/renderer/backend/gles/formats_gles.h" #include "impeller/renderer/backend/gles/sampler_gles.h" #include "impeller/renderer/backend/gles/texture_gles.h" +#include "impeller/renderer/command.h" namespace impeller { @@ -100,6 +103,38 @@ bool BufferBindingsGLES::ReadUniformsBindings(const ProcTableGLES& gl, if (!gl.IsProgram(program)) { return false; } + program_handle_ = program; + if (gl.GetDescription()->GetGlVersion().IsAtLeast(Version{3, 0, 0})) { + return ReadUniformsBindingsV3(gl, program); + } + return ReadUniformsBindingsV2(gl, program); +} + +bool BufferBindingsGLES::ReadUniformsBindingsV3(const ProcTableGLES& gl, + GLuint program) { + program_handle_ = program; + GLint uniform_blocks = 0; + gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &uniform_blocks); + for (GLint i = 0; i < uniform_blocks; i++) { + GLint name_length = 0; + gl.GetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_NAME_LENGTH, + &name_length); + + std::vector name; + name.resize(name_length); + GLint length = 0; + gl.GetActiveUniformBlockName(program, i, name_length, &length, name.data()); + + GLuint block_index = gl.GetUniformBlockIndex(program, name.data()); + ubo_locations_[std::string{name.data(), static_cast(length)}] = + std::make_pair(block_index, i); + } + use_ubo_ = true; + return ReadUniformsBindingsV2(gl, program); +} + +bool BufferBindingsGLES::ReadUniformsBindingsV2(const ProcTableGLES& gl, + GLuint program) { GLint max_name_size = 0; gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_size); @@ -138,6 +173,9 @@ bool BufferBindingsGLES::ReadUniformsBindings(const ProcTableGLES& gl, auto location = gl.GetUniformLocation(program, name.data()); if (location == -1) { + if (use_ubo_) { + continue; + } VALIDATION_LOG << "Could not query the location of an active uniform."; return false; } @@ -179,28 +217,23 @@ bool BufferBindingsGLES::BindVertexAttributes(const ProcTableGLES& gl, return true; } -bool BufferBindingsGLES::BindUniformData(const ProcTableGLES& gl, - Allocator& transients_allocator, - const Bindings& vertex_bindings, - const Bindings& fragment_bindings) { - for (const auto& buffer : vertex_bindings.buffers) { - if (!BindUniformBuffer(gl, transients_allocator, buffer.view)) { - return false; - } - } - for (const auto& buffer : fragment_bindings.buffers) { - if (!BindUniformBuffer(gl, transients_allocator, buffer.view)) { +bool BufferBindingsGLES::BindUniformData( + const ProcTableGLES& gl, + const std::vector& bound_textures, + const std::vector& bound_buffers, + Range texture_range, + Range buffer_range) { + for (auto i = 0u; i < buffer_range.length; i++) { + if (!BindUniformBuffer(gl, bound_buffers[buffer_range.offset + i])) { return false; } } - std::optional next_unit_index = - BindTextures(gl, vertex_bindings, ShaderStage::kVertex); + BindTextures(gl, bound_textures, texture_range, ShaderStage::kVertex); if (!next_unit_index.has_value()) { return false; } - - if (!BindTextures(gl, fragment_bindings, ShaderStage::kFragment, + if (!BindTextures(gl, bound_textures, texture_range, ShaderStage::kFragment, *next_unit_index) .has_value()) { return false; @@ -242,15 +275,16 @@ GLint BufferBindingsGLES::ComputeTextureLocation( const std::vector& BufferBindingsGLES::ComputeUniformLocations( const ShaderMetadata* metadata) { - auto location = binding_map_.find(metadata->name); + BindingMap::iterator location = binding_map_.find(metadata->name); if (location != binding_map_.end()) { return location->second; } // For each metadata member, look up the binding location and record // it in the binding map. - auto& locations = binding_map_[metadata->name] = {}; - for (const auto& member : metadata->members) { + std::vector& locations = binding_map_[metadata->name] = {}; + locations.reserve(metadata->members.size()); + for (const ShaderStructMemberMetadata& member : metadata->members) { if (member.type == ShaderType::kVoid) { // Void types are used for padding. We are obviously not going to find // mappings for these. Keep going. @@ -259,9 +293,10 @@ const std::vector& BufferBindingsGLES::ComputeUniformLocations( } size_t element_count = member.array_elements.value_or(1); - const auto member_key = + const std::string member_key = CreateUniformMemberKey(metadata->name, member.name, element_count > 1); - const auto computed_location = uniform_locations_.find(member_key); + const absl::flat_hash_map::iterator computed_location = + uniform_locations_.find(member_key); if (computed_location == uniform_locations_.end()) { // Uniform was not active. locations.push_back(-1); @@ -273,17 +308,56 @@ const std::vector& BufferBindingsGLES::ComputeUniformLocations( } bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl, - Allocator& transients_allocator, const BufferResource& buffer) { - const auto* metadata = buffer.GetMetadata(); - auto device_buffer = buffer.resource.GetBuffer(); + const ShaderMetadata* metadata = buffer.GetMetadata(); + const DeviceBuffer* device_buffer = buffer.resource.GetBuffer(); if (!device_buffer) { VALIDATION_LOG << "Device buffer not found."; return false; } - const auto& device_buffer_gles = DeviceBufferGLES::Cast(*device_buffer); + const DeviceBufferGLES& device_buffer_gles = + DeviceBufferGLES::Cast(*device_buffer); + + if (use_ubo_) { + return BindUniformBufferV3(gl, buffer.resource, metadata, + device_buffer_gles); + } + return BindUniformBufferV2(gl, buffer.resource, metadata, device_buffer_gles); +} + +bool BufferBindingsGLES::BindUniformBufferV3( + const ProcTableGLES& gl, + const BufferView& buffer, + const ShaderMetadata* metadata, + const DeviceBufferGLES& device_buffer_gles) { + absl::flat_hash_map>::iterator it = + ubo_locations_.find(metadata->name); + if (it == ubo_locations_.end()) { + return BindUniformBufferV2(gl, buffer, metadata, device_buffer_gles); + } + const auto& [block_index, binding_point] = it->second; + gl.UniformBlockBinding(program_handle_, block_index, binding_point); + + if (!device_buffer_gles.BindAndUploadDataIfNecessary( + DeviceBufferGLES::BindingType::kUniformBuffer)) { + return false; + } + auto handle = device_buffer_gles.GetHandle(); + if (!handle.has_value()) { + return false; + } + gl.BindBufferRange(GL_UNIFORM_BUFFER, binding_point, handle.value(), + buffer.GetRange().offset, buffer.GetRange().length); + return true; +} + +bool BufferBindingsGLES::BindUniformBufferV2( + const ProcTableGLES& gl, + const BufferView& buffer, + const ShaderMetadata* metadata, + const DeviceBufferGLES& device_buffer_gles) { const uint8_t* buffer_ptr = - device_buffer_gles.GetBufferData() + buffer.resource.GetRange().offset; + device_buffer_gles.GetBufferData() + buffer.GetRange().offset; if (metadata->members.empty()) { VALIDATION_LOG << "Uniform buffer had no members. This is currently " @@ -292,10 +366,10 @@ bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl, return false; } - const auto& locations = ComputeUniformLocations(metadata); - for (auto i = 0u; i < metadata->members.size(); i++) { - const auto& member = metadata->members[i]; - auto location = locations[i]; + const std::vector& locations = ComputeUniformLocations(metadata); + for (size_t i = 0u; i < metadata->members.size(); i++) { + const ShaderStructMemberMetadata& member = metadata->members[i]; + GLint location = locations[i]; // Void type or inactive uniform. if (location == -1 || member.type == ShaderType::kVoid) { continue; @@ -309,77 +383,59 @@ bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl, // When binding uniform arrays, the elements must be contiguous. Copy // the uniforms to a temp buffer to eliminate any padding needed by the // other backends if the array elements have padding. - std::vector array_element_buffer_; + std::vector array_element_buffer; if (element_count > 1 && element_stride != member.size) { - array_element_buffer_.resize(member.size * element_count); + array_element_buffer.resize(member.size * element_count); for (size_t element_i = 0; element_i < element_count; element_i++) { - std::memcpy(array_element_buffer_.data() + element_i * member.size, + std::memcpy(array_element_buffer.data() + element_i * member.size, reinterpret_cast(buffer_data) + element_i * element_stride, member.size); } buffer_data = - reinterpret_cast(array_element_buffer_.data()); + reinterpret_cast(array_element_buffer.data()); + } + + if (member.type != ShaderType::kFloat) { + VALIDATION_LOG << "Could not bind uniform buffer data for key: " + << member.name << " : " << static_cast(member.type); + return false; } - switch (member.type) { - case ShaderType::kFloat: - switch (member.size) { - case sizeof(Matrix): - gl.UniformMatrix4fv(location, // location - element_count, // count - GL_FALSE, // normalize - buffer_data // data - ); - continue; - case sizeof(Vector4): - gl.Uniform4fv(location, // location - element_count, // count - buffer_data // data - ); - continue; - case sizeof(Vector3): - gl.Uniform3fv(location, // location - element_count, // count - buffer_data // data - ); - continue; - case sizeof(Vector2): - gl.Uniform2fv(location, // location - element_count, // count - buffer_data // data - ); - continue; - case sizeof(Scalar): - gl.Uniform1fv(location, // location - element_count, // count - buffer_data // data - ); - continue; - } - VALIDATION_LOG << "Size " << member.size - << " could not be mapped ShaderType::kFloat for key: " - << member.name; - case ShaderType::kBoolean: - case ShaderType::kSignedByte: - case ShaderType::kUnsignedByte: - case ShaderType::kSignedShort: - case ShaderType::kUnsignedShort: - case ShaderType::kSignedInt: - case ShaderType::kUnsignedInt: - case ShaderType::kSignedInt64: - case ShaderType::kUnsignedInt64: - case ShaderType::kAtomicCounter: - case ShaderType::kUnknown: - case ShaderType::kVoid: - case ShaderType::kHalfFloat: - case ShaderType::kDouble: - case ShaderType::kStruct: - case ShaderType::kImage: - case ShaderType::kSampledImage: - case ShaderType::kSampler: - VALIDATION_LOG << "Could not bind uniform buffer data for key: " - << member.name << " : " << static_cast(member.type); + switch (member.size) { + case sizeof(Matrix): + gl.UniformMatrix4fv(location, // location + element_count, // count + GL_FALSE, // normalize + buffer_data // data + ); + continue; + case sizeof(Vector4): + gl.Uniform4fv(location, // location + element_count, // count + buffer_data // data + ); + continue; + case sizeof(Vector3): + gl.Uniform3fv(location, // location + element_count, // count + buffer_data // data + ); + continue; + case sizeof(Vector2): + gl.Uniform2fv(location, // location + element_count, // count + buffer_data // data + ); + continue; + case sizeof(Scalar): + gl.Uniform1fv(location, // location + element_count, // count + buffer_data // data + ); + continue; + default: + VALIDATION_LOG << "Invalid member size binding: " << member.size; return false; } } @@ -388,11 +444,16 @@ bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl, std::optional BufferBindingsGLES::BindTextures( const ProcTableGLES& gl, - const Bindings& bindings, + const std::vector& bound_textures, + Range texture_range, ShaderStage stage, size_t unit_start_index) { size_t active_index = unit_start_index; - for (const auto& data : bindings.sampled_images) { + for (auto i = 0u; i < texture_range.length; i++) { + const TextureAndSampler& data = bound_textures[texture_range.offset + i]; + if (data.stage != stage) { + continue; + } const auto& texture_gles = TextureGLES::Cast(*data.texture.resource); if (data.texture.GetMetadata() == nullptr) { VALIDATION_LOG << "No metadata found for texture binding."; diff --git a/impeller/renderer/backend/gles/buffer_bindings_gles.h b/impeller/renderer/backend/gles/buffer_bindings_gles.h index 65642d8db33c8..29f032da76cf9 100644 --- a/impeller/renderer/backend/gles/buffer_bindings_gles.h +++ b/impeller/renderer/backend/gles/buffer_bindings_gles.h @@ -8,13 +8,19 @@ #include #include +#include "flutter/third_party/abseil-cpp/absl/container/flat_hash_map.h" #include "impeller/core/shader_types.h" +#include "impeller/renderer/backend/gles/device_buffer_gles.h" #include "impeller/renderer/backend/gles/gles.h" #include "impeller/renderer/backend/gles/proc_table_gles.h" #include "impeller/renderer/command.h" namespace impeller { +namespace testing { +FML_TEST_CLASS(BufferBindingsGLESTest, BindUniformData); +} // namespace testing + //------------------------------------------------------------------------------ /// @brief Sets up stage bindings for single draw call in the OpenGLES /// backend. @@ -37,13 +43,15 @@ class BufferBindingsGLES { size_t vertex_offset); bool BindUniformData(const ProcTableGLES& gl, - Allocator& transients_allocator, - const Bindings& vertex_bindings, - const Bindings& fragment_bindings); + const std::vector& bound_textures, + const std::vector& bound_buffers, + Range texture_range, + Range buffer_range); bool UnbindVertexAttributes(const ProcTableGLES& gl); private: + FML_FRIEND_TEST(testing::BufferBindingsGLESTest, BindUniformData); //---------------------------------------------------------------------------- /// @brief The arguments to glVertexAttribPointer. /// @@ -57,29 +65,52 @@ class BufferBindingsGLES { }; std::vector> vertex_attrib_arrays_; - std::unordered_map uniform_locations_; + absl::flat_hash_map uniform_locations_; + absl::flat_hash_map> ubo_locations_; - using BindingMap = std::unordered_map>; + using BindingMap = absl::flat_hash_map>; BindingMap binding_map_ = {}; GLuint vertex_array_object_ = 0; + GLuint program_handle_ = GL_NONE; + bool use_ubo_ = false; const std::vector& ComputeUniformLocations( const ShaderMetadata* metadata); + bool ReadUniformsBindingsV2(const ProcTableGLES& gl, GLuint program); + + bool ReadUniformsBindingsV3(const ProcTableGLES& gl, GLuint program); + GLint ComputeTextureLocation(const ShaderMetadata* metadata); - bool BindUniformBuffer(const ProcTableGLES& gl, - Allocator& transients_allocator, - const BufferResource& buffer); + bool BindUniformBuffer(const ProcTableGLES& gl, const BufferResource& buffer); + + bool BindUniformBufferV2(const ProcTableGLES& gl, + const BufferView& buffer, + const ShaderMetadata* metadata, + const DeviceBufferGLES& device_buffer_gles); - std::optional BindTextures(const ProcTableGLES& gl, - const Bindings& bindings, - ShaderStage stage, - size_t unit_start_index = 0); + bool BindUniformBufferV3(const ProcTableGLES& gl, + const BufferView& buffer, + const ShaderMetadata* metadata, + const DeviceBufferGLES& device_buffer_gles); + + std::optional BindTextures( + const ProcTableGLES& gl, + const std::vector& bound_textures, + Range texture_range, + ShaderStage stage, + size_t unit_start_index = 0); BufferBindingsGLES(const BufferBindingsGLES&) = delete; BufferBindingsGLES& operator=(const BufferBindingsGLES&) = delete; + + // For testing. + void SetUniformBindings( + absl::flat_hash_map uniform_locations) { + uniform_locations_ = std::move(uniform_locations); + } }; } // namespace impeller diff --git a/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc b/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc new file mode 100644 index 0000000000000..45a342bfcbd06 --- /dev/null +++ b/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc @@ -0,0 +1,51 @@ +// 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/testing/testing.h" // IWYU pragma: keep +#include "gtest/gtest.h" +#include "impeller/renderer/backend/gles/buffer_bindings_gles.h" +#include "impeller/renderer/backend/gles/device_buffer_gles.h" +#include "impeller/renderer/backend/gles/test/mock_gles.h" +#include "impeller/renderer/command.h" + +namespace impeller { +namespace testing { + +using ::testing::_; + +TEST(BufferBindingsGLESTest, BindUniformData) { + BufferBindingsGLES bindings; + absl::flat_hash_map uniform_bindings; + uniform_bindings["SHADERMETADATA.FOOBAR"] = 1; + bindings.SetUniformBindings(std::move(uniform_bindings)); + auto mock_gles_impl = std::make_unique(); + + EXPECT_CALL(*mock_gles_impl, Uniform1fv(_, _, _)).Times(1); + + std::shared_ptr mock_gl = MockGLES::Init(std::move(mock_gles_impl)); + std::vector bound_buffers; + std::vector bound_textures; + + ShaderMetadata shader_metadata = { + .name = "shader_metadata", + .members = {ShaderStructMemberMetadata{.type = ShaderType::kFloat, + .name = "foobar", + .offset = 0, + .size = sizeof(float), + .byte_length = sizeof(float)}}}; + std::shared_ptr reactor; + std::shared_ptr backing_store = std::make_shared(); + ASSERT_TRUE(backing_store->Truncate(Bytes{sizeof(float)})); + DeviceBufferGLES device_buffer(DeviceBufferDescriptor{.size = sizeof(float)}, + reactor, backing_store); + BufferView buffer_view(&device_buffer, Range(0, sizeof(float))); + bound_buffers.push_back(BufferResource(&shader_metadata, buffer_view)); + + EXPECT_TRUE(bindings.BindUniformData(mock_gl->GetProcTable(), bound_textures, + bound_buffers, Range{0, 0}, + Range{0, 1})); +} + +} // namespace testing +} // namespace impeller diff --git a/impeller/renderer/backend/gles/capabilities_gles.cc b/impeller/renderer/backend/gles/capabilities_gles.cc index 2f3c4882851fa..67f73eff4e07f 100644 --- a/impeller/renderer/backend/gles/capabilities_gles.cc +++ b/impeller/renderer/backend/gles/capabilities_gles.cc @@ -22,6 +22,10 @@ static const constexpr char* kNvidiaTextureBorderClampExt = static const constexpr char* kMultisampledRenderToTextureExt = "GL_EXT_multisampled_render_to_texture"; +// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture2.txt +static const constexpr char* kMultisampledRenderToTexture2Ext = + "GL_EXT_multisampled_render_to_texture2"; + CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) { { GLint value = 0; @@ -123,10 +127,12 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) { if (desc->HasExtension(kMultisampledRenderToTextureExt)) { supports_implicit_msaa_ = true; - // We hard-code 4x MSAA, so let's make sure it's supported. - GLint value = 0; - gl.GetIntegerv(GL_MAX_SAMPLES_EXT, &value); - supports_offscreen_msaa_ = value >= 4; + if (desc->HasExtension(kMultisampledRenderToTexture2Ext)) { + // We hard-code 4x MSAA, so let's make sure it's supported. + GLint value = 0; + gl.GetIntegerv(GL_MAX_SAMPLES_EXT, &value); + supports_offscreen_msaa_ = value >= 4; + } } is_es_ = desc->IsES(); is_angle_ = desc->IsANGLE(); diff --git a/impeller/renderer/backend/gles/command_buffer_gles.cc b/impeller/renderer/backend/gles/command_buffer_gles.cc index 4e0831f9e3a10..4cd6b279b9e18 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.cc +++ b/impeller/renderer/backend/gles/command_buffer_gles.cc @@ -11,7 +11,7 @@ namespace impeller { CommandBufferGLES::CommandBufferGLES(std::weak_ptr context, - ReactorGLES::Ref reactor) + std::shared_ptr reactor) : CommandBuffer(std::move(context)), reactor_(std::move(reactor)), is_valid_(reactor_ && reactor_->IsValid()) {} diff --git a/impeller/renderer/backend/gles/command_buffer_gles.h b/impeller/renderer/backend/gles/command_buffer_gles.h index 09570b19a955b..c7baea2d7bf15 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.h +++ b/impeller/renderer/backend/gles/command_buffer_gles.h @@ -19,11 +19,11 @@ class CommandBufferGLES final : public CommandBuffer { private: friend class ContextGLES; - ReactorGLES::Ref reactor_; + std::shared_ptr reactor_; bool is_valid_ = false; CommandBufferGLES(std::weak_ptr context, - ReactorGLES::Ref reactor); + std::shared_ptr reactor); // |CommandBuffer| void SetLabel(std::string_view label) const override; diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index ba98e78f5cbe5..f8cf2841cd013 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -7,6 +7,8 @@ #include "impeller/base/config.h" #include "impeller/base/validation.h" +#include "impeller/base/version.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/gles/command_buffer_gles.h" #include "impeller/renderer/backend/gles/gpu_tracer_gles.h" #include "impeller/renderer/backend/gles/handle_gles.h" @@ -81,7 +83,7 @@ Context::BackendType ContextGLES::GetBackendType() const { return Context::BackendType::kOpenGLES; } -const ReactorGLES::Ref& ContextGLES::GetReactor() const { +const std::shared_ptr& ContextGLES::GetReactor() const { return reactor_; } @@ -180,4 +182,13 @@ bool ContextGLES::AddTrackingFence( return true; } +// |Context| +RuntimeStageBackend ContextGLES::GetRuntimeStageBackend() const { + if (GetReactor()->GetProcTable().GetDescription()->GetGlVersion().IsAtLeast( + Version{3, 0, 0})) { + return RuntimeStageBackend::kOpenGLES3; + } + return RuntimeStageBackend::kOpenGLES; +} + } // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 1c2587cc0d276..2e7e87a01c9fd 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -6,6 +6,7 @@ #define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_CONTEXT_GLES_H_ #include "impeller/base/backend_cast.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/gles/allocator_gles.h" #include "impeller/renderer/backend/gles/capabilities_gles.h" #include "impeller/renderer/backend/gles/gpu_tracer_gles.h" @@ -34,7 +35,7 @@ class ContextGLES final : public Context, // |Context| BackendType GetBackendType() const override; - const ReactorGLES::Ref& GetReactor() const; + const std::shared_ptr& GetReactor() const; std::optional AddReactorWorker( const std::shared_ptr& worker); @@ -44,7 +45,7 @@ class ContextGLES final : public Context, std::shared_ptr GetGPUTracer() const { return gpu_tracer_; } private: - ReactorGLES::Ref reactor_; + std::shared_ptr reactor_; std::shared_ptr shader_library_; std::shared_ptr pipeline_library_; std::shared_ptr sampler_library_; @@ -106,6 +107,9 @@ class ContextGLES final : public Context, // |Context| [[nodiscard]] bool FlushCommandBuffers() override; + // |Context| + RuntimeStageBackend GetRuntimeStageBackend() const override; + ContextGLES(const ContextGLES&) = delete; ContextGLES& operator=(const ContextGLES&) = delete; diff --git a/impeller/renderer/backend/gles/device_buffer_gles.cc b/impeller/renderer/backend/gles/device_buffer_gles.cc index f4caaf5af874d..0a7478d8f7e95 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.cc +++ b/impeller/renderer/backend/gles/device_buffer_gles.cc @@ -13,18 +13,16 @@ namespace impeller { DeviceBufferGLES::DeviceBufferGLES(DeviceBufferDescriptor desc, - ReactorGLES::Ref reactor, + std::shared_ptr reactor, std::shared_ptr backing_store) : DeviceBuffer(desc), reactor_(std::move(reactor)), - handle_(reactor_ ? reactor_->CreateHandle(HandleType::kBuffer) - : HandleGLES::DeadHandle()), backing_store_(std::move(backing_store)) {} // |DeviceBuffer| DeviceBufferGLES::~DeviceBufferGLES() { - if (!handle_.IsDead()) { - reactor_->CollectHandle(handle_); + if (handle_.has_value() && !handle_->IsDead()) { + reactor_->CollectHandle(*handle_); } } @@ -56,6 +54,14 @@ bool DeviceBufferGLES::OnCopyHostBuffer(const uint8_t* source, return true; } +std::optional DeviceBufferGLES::GetHandle() const { + if (handle_.has_value()) { + return reactor_->GetGLHandle(*handle_); + } else { + return std::nullopt; + } +} + void DeviceBufferGLES::Flush(std::optional range) const { if (!range.has_value()) { dirty_range_ = Range{ @@ -75,6 +81,8 @@ static GLenum ToTarget(DeviceBufferGLES::BindingType type) { return GL_ARRAY_BUFFER; case DeviceBufferGLES::BindingType::kElementArrayBuffer: return GL_ELEMENT_ARRAY_BUFFER; + case DeviceBufferGLES::BindingType::kUniformBuffer: + return GL_UNIFORM_BUFFER; } FML_UNREACHABLE(); } @@ -84,7 +92,16 @@ bool DeviceBufferGLES::BindAndUploadDataIfNecessary(BindingType type) const { return false; } - auto buffer = reactor_->GetGLHandle(handle_); + if (!handle_.has_value()) { + handle_ = reactor_->CreateUntrackedHandle(HandleType::kBuffer); +#ifdef IMPELLER_DEBUG + if (handle_.has_value() && label_.has_value()) { + reactor_->SetDebugLabel(*handle_, *label_); + } +#endif + } + + auto buffer = reactor_->GetGLHandle(*handle_); if (!buffer.has_value()) { return false; } @@ -112,7 +129,10 @@ bool DeviceBufferGLES::BindAndUploadDataIfNecessary(BindingType type) const { // |DeviceBuffer| bool DeviceBufferGLES::SetLabel(std::string_view label) { #ifdef IMPELLER_DEBUG - reactor_->SetDebugLabel(handle_, label); + label_ = label; + if (handle_.has_value()) { + reactor_->SetDebugLabel(*handle_, label); + } #endif // IMPELLER_DEBUG return true; } diff --git a/impeller/renderer/backend/gles/device_buffer_gles.h b/impeller/renderer/backend/gles/device_buffer_gles.h index a18e010dc2649..f080d4e3e0ffe 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.h +++ b/impeller/renderer/backend/gles/device_buffer_gles.h @@ -20,7 +20,7 @@ class DeviceBufferGLES final public BackendCast { public: DeviceBufferGLES(DeviceBufferDescriptor desc, - ReactorGLES::Ref reactor, + std::shared_ptr reactor, std::shared_ptr backing_store); // |DeviceBuffer| @@ -34,15 +34,20 @@ class DeviceBufferGLES final enum class BindingType { kArrayBuffer, kElementArrayBuffer, + kUniformBuffer, }; [[nodiscard]] bool BindAndUploadDataIfNecessary(BindingType type) const; void Flush(std::optional range = std::nullopt) const override; + std::optional GetHandle() const; + private: - ReactorGLES::Ref reactor_; - HandleGLES handle_; + std::shared_ptr reactor_; + std::optional label_; + // Mutable for lazy evaluation. + mutable std::optional handle_; mutable std::shared_ptr backing_store_; mutable std::optional dirty_range_ = std::nullopt; mutable bool initialized_ = false; diff --git a/impeller/renderer/backend/gles/device_buffer_gles_unittests.cc b/impeller/renderer/backend/gles/device_buffer_gles_unittests.cc new file mode 100644 index 0000000000000..1fe910faab0d9 --- /dev/null +++ b/impeller/renderer/backend/gles/device_buffer_gles_unittests.cc @@ -0,0 +1,49 @@ +// 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/testing/testing.h" // IWYU pragma: keep +#include "gtest/gtest.h" +#include "impeller/renderer/backend/gles/device_buffer_gles.h" +#include "impeller/renderer/backend/gles/test/mock_gles.h" + +namespace impeller { +namespace testing { + +using ::testing::_; + +namespace { +class TestWorker : public ReactorGLES::Worker { + public: + bool CanReactorReactOnCurrentThreadNow( + const ReactorGLES& reactor) const override { + return true; + } +}; +} // namespace + +TEST(DeviceBufferGLESTest, BindUniformData) { + auto mock_gles_impl = std::make_unique(); + + EXPECT_CALL(*mock_gles_impl, GenBuffers(1, _)).Times(1); + + std::shared_ptr mock_gled = + MockGLES::Init(std::move(mock_gles_impl)); + ProcTableGLES::Resolver resolver = kMockResolverGLES; + auto proc_table = std::make_unique(resolver); + auto worker = std::make_shared(); + auto reactor = std::make_shared(std::move(proc_table)); + reactor->AddWorker(worker); + + std::shared_ptr backing_store = std::make_shared(); + ASSERT_TRUE(backing_store->Truncate(Bytes{sizeof(float)})); + DeviceBufferGLES device_buffer(DeviceBufferDescriptor{.size = sizeof(float)}, + reactor, backing_store); + EXPECT_FALSE(device_buffer.GetHandle().has_value()); + EXPECT_TRUE(device_buffer.BindAndUploadDataIfNecessary( + DeviceBufferGLES::BindingType::kUniformBuffer)); + EXPECT_TRUE(device_buffer.GetHandle().has_value()); +} + +} // namespace testing +} // namespace impeller diff --git a/impeller/renderer/backend/gles/handle_gles.h b/impeller/renderer/backend/gles/handle_gles.h index 3e7b44f0320b0..808918fe8e3a7 100644 --- a/impeller/renderer/backend/gles/handle_gles.h +++ b/impeller/renderer/backend/gles/handle_gles.h @@ -34,10 +34,8 @@ class ReactorGLES; /// OpenGL object handles, these handles can be collected on any /// thread as long as their destruction is scheduled in a reactor. /// -struct HandleGLES { - HandleType type = HandleType::kUnknown; - std::optional name; - +class HandleGLES { + public: //---------------------------------------------------------------------------- /// @brief Creates a dead handle. /// @@ -52,7 +50,7 @@ struct HandleGLES { /// /// @return True if dead, False otherwise. /// - constexpr bool IsDead() const { return !name.has_value(); } + constexpr bool IsDead() const { return !name_.has_value(); } //---------------------------------------------------------------------------- /// @brief Get the hash value of this handle. Handles can be used as map @@ -60,9 +58,7 @@ struct HandleGLES { /// struct Hash { std::size_t operator()(const HandleGLES& handle) const { - return fml::HashCombine( - std::underlying_type_t(handle.type), - handle.name); + return handle.GetHash(); } }; @@ -71,17 +67,33 @@ struct HandleGLES { /// struct Equal { bool operator()(const HandleGLES& lhs, const HandleGLES& rhs) const { - return lhs.type == rhs.type && lhs.name == rhs.name; + return lhs.type_ == rhs.type_ && lhs.name_ == rhs.name_; } }; + HandleType GetType() const { return type_; } + const std::optional& GetName() const { return name_; } + std::size_t GetHash() const { return hash_; } + private: + HandleType type_ = HandleType::kUnknown; + std::optional name_; + std::size_t hash_; + std::optional untracked_id_; + friend class ReactorGLES; - HandleGLES(HandleType p_type, UniqueID p_name) : type(p_type), name(p_name) {} + HandleGLES(HandleType p_type, UniqueID p_name) + : type_(p_type), + name_(p_name), + hash_(fml::HashCombine(std::underlying_type_t(p_type), + p_name)) {} HandleGLES(HandleType p_type, std::optional p_name) - : type(p_type), name(p_name) {} + : type_(p_type), + name_(p_name), + hash_(fml::HashCombine(std::underlying_type_t(p_type), + p_name)) {} static HandleGLES Create(HandleType type) { return HandleGLES{type, UniqueID{}}; @@ -94,12 +106,13 @@ namespace std { inline std::ostream& operator<<(std::ostream& out, const impeller::HandleGLES& handle) { - out << HandleTypeToString(handle.type) << "("; + out << HandleTypeToString(handle.GetType()) << "("; if (handle.IsDead()) { out << "DEAD"; } else { - if (handle.name.has_value()) { - out << handle.name.value().id; + const std::optional& name = handle.GetName(); + if (name.has_value()) { + out << name.value().id; } else { out << "UNNAMED"; } diff --git a/impeller/renderer/backend/gles/pipeline_gles.cc b/impeller/renderer/backend/gles/pipeline_gles.cc index 557eca2b48443..e173ce167be85 100644 --- a/impeller/renderer/backend/gles/pipeline_gles.cc +++ b/impeller/renderer/backend/gles/pipeline_gles.cc @@ -6,7 +6,7 @@ namespace impeller { -PipelineGLES::PipelineGLES(ReactorGLES::Ref reactor, +PipelineGLES::PipelineGLES(std::shared_ptr reactor, std::weak_ptr library, const PipelineDescriptor& desc, std::shared_ptr handle) diff --git a/impeller/renderer/backend/gles/pipeline_gles.h b/impeller/renderer/backend/gles/pipeline_gles.h index e8a3ae8225bf4..0db8414f9a418 100644 --- a/impeller/renderer/backend/gles/pipeline_gles.h +++ b/impeller/renderer/backend/gles/pipeline_gles.h @@ -38,7 +38,7 @@ class PipelineGLES final private: friend PipelineLibraryGLES; - ReactorGLES::Ref reactor_; + std::shared_ptr reactor_; std::shared_ptr handle_; std::unique_ptr buffer_bindings_; bool is_valid_ = false; @@ -46,7 +46,7 @@ class PipelineGLES final // |Pipeline| bool IsValid() const override; - PipelineGLES(ReactorGLES::Ref reactor, + PipelineGLES(std::shared_ptr reactor, std::weak_ptr library, const PipelineDescriptor& desc, std::shared_ptr handle); diff --git a/impeller/renderer/backend/gles/pipeline_library_gles.cc b/impeller/renderer/backend/gles/pipeline_library_gles.cc index 493aabd926c83..199af7068ac26 100644 --- a/impeller/renderer/backend/gles/pipeline_library_gles.cc +++ b/impeller/renderer/backend/gles/pipeline_library_gles.cc @@ -16,7 +16,7 @@ namespace impeller { -PipelineLibraryGLES::PipelineLibraryGLES(ReactorGLES::Ref reactor) +PipelineLibraryGLES::PipelineLibraryGLES(std::shared_ptr reactor) : reactor_(std::move(reactor)) {} static std::string GetShaderInfoLog(const ProcTableGLES& gl, GLuint shader) { @@ -212,7 +212,8 @@ std::shared_ptr PipelineLibraryGLES::CreatePipeline( desc, // has_cached_program ? std::move(cached_program) - : std::make_shared(reactor, HandleType::kProgram))); + : std::make_shared(UniqueHandleGLES::MakeUntracked( + reactor, HandleType::kProgram)))); auto program = reactor->GetGLHandle(pipeline->GetProgramHandle()); @@ -323,7 +324,7 @@ void PipelineLibraryGLES::RemovePipelinesWithEntryPoint( // |PipelineLibrary| PipelineLibraryGLES::~PipelineLibraryGLES() = default; -const ReactorGLES::Ref& PipelineLibraryGLES::GetReactor() const { +const std::shared_ptr& PipelineLibraryGLES::GetReactor() const { return reactor_; } diff --git a/impeller/renderer/backend/gles/pipeline_library_gles.h b/impeller/renderer/backend/gles/pipeline_library_gles.h index e8b5c0433d88a..3b9f29f7d2274 100644 --- a/impeller/renderer/backend/gles/pipeline_library_gles.h +++ b/impeller/renderer/backend/gles/pipeline_library_gles.h @@ -87,12 +87,12 @@ class PipelineLibraryGLES final ProgramKey::Hash, ProgramKey::Equal>; - ReactorGLES::Ref reactor_; + std::shared_ptr reactor_; PipelineMap pipelines_; Mutex programs_mutex_; ProgramMap programs_ IPLR_GUARDED_BY(programs_mutex_); - explicit PipelineLibraryGLES(ReactorGLES::Ref reactor); + explicit PipelineLibraryGLES(std::shared_ptr reactor); // |PipelineLibrary| bool IsValid() const override; @@ -113,7 +113,7 @@ class PipelineLibraryGLES final void RemovePipelinesWithEntryPoint( std::shared_ptr function) override; - const ReactorGLES::Ref& GetReactor() const; + const std::shared_ptr& GetReactor() const; static std::shared_ptr CreatePipeline( const std::weak_ptr& weak_library, diff --git a/impeller/renderer/backend/gles/proc_table_gles.cc b/impeller/renderer/backend/gles/proc_table_gles.cc index cf2482d6fb6e2..c4450e7b3b673 100644 --- a/impeller/renderer/backend/gles/proc_table_gles.cc +++ b/impeller/renderer/backend/gles/proc_table_gles.cc @@ -6,7 +6,6 @@ #include -#include "fml/closure.h" #include "impeller/base/allocation.h" #include "impeller/base/comparable.h" #include "impeller/base/strings.h" @@ -180,12 +179,12 @@ void ProcTableGLES::ShaderSourceMapping( std::optional ProcTableGLES::ComputeShaderWithDefines( const fml::Mapping& mapping, const std::vector& defines) const { - auto shader_source = std::string{ + std::string shader_source = std::string{ reinterpret_cast(mapping.GetMapping()), mapping.GetSize()}; // Look for the first newline after the '#version' header, which impellerc // will always emit as the first line of a compiled shader. - auto index = shader_source.find('\n'); + size_t index = shader_source.find('\n'); if (index == std::string::npos) { VALIDATION_LOG << "Failed to append constant data to shader"; return std::nullopt; @@ -360,7 +359,7 @@ static bool ResourceIsLive(const ProcTableGLES& gl, bool ProcTableGLES::SetDebugLabel(DebugResourceType type, GLint name, - const std::string& label) const { + std::string_view label) const { if (debug_label_max_length_ <= 0) { return true; } diff --git a/impeller/renderer/backend/gles/proc_table_gles.h b/impeller/renderer/backend/gles/proc_table_gles.h index f17c42949d9cb..ccc499af9dcca 100644 --- a/impeller/renderer/backend/gles/proc_table_gles.h +++ b/impeller/renderer/backend/gles/proc_table_gles.h @@ -241,6 +241,11 @@ void(glDepthRange)(GLdouble n, GLdouble f); #define FOR_EACH_IMPELLER_GLES3_PROC(PROC) \ PROC(FenceSync); \ PROC(DeleteSync); \ + PROC(GetActiveUniformBlockiv); \ + PROC(GetActiveUniformBlockName); \ + PROC(GetUniformBlockIndex); \ + PROC(UniformBlockBinding); \ + PROC(BindBufferRange); \ PROC(WaitSync); \ PROC(BlitFramebuffer); @@ -311,7 +316,7 @@ class ProcTableGLES { bool SetDebugLabel(DebugResourceType type, GLint name, - const std::string& label) const; + std::string_view label) const; void PushDebugGroup(const std::string& string) const; diff --git a/impeller/renderer/backend/gles/reactor_gles.cc b/impeller/renderer/backend/gles/reactor_gles.cc index 82266bfd998eb..726bcd2d37310 100644 --- a/impeller/renderer/backend/gles/reactor_gles.cc +++ b/impeller/renderer/backend/gles/reactor_gles.cc @@ -84,7 +84,7 @@ ReactorGLES::~ReactorGLES() { if (CanReactOnCurrentThread()) { for (auto& handle : handles_) { if (handle.second.name.has_value()) { - CollectGLHandle(*proc_table_, handle.first.type, + CollectGLHandle(*proc_table_, handle.first.GetType(), handle.second.name.value()); } } @@ -126,6 +126,10 @@ const ProcTableGLES& ReactorGLES::GetProcTable() const { std::optional ReactorGLES::GetHandle( const HandleGLES& handle) const { + if (handle.untracked_id_.has_value()) { + return ReactorGLES::GLStorage{.integer = handle.untracked_id_.value()}; + } + ReaderLock handles_lock(handles_mutex_); if (auto found = handles_.find(handle); found != handles_.end()) { if (found->second.pending_collection) { @@ -145,7 +149,7 @@ std::optional ReactorGLES::GetHandle( } std::optional ReactorGLES::GetGLHandle(const HandleGLES& handle) const { - if (handle.type == HandleType::kFence) { + if (handle.GetType() == HandleType::kFence) { return std::nullopt; } std::optional gl_handle = GetHandle(handle); @@ -156,7 +160,7 @@ std::optional ReactorGLES::GetGLHandle(const HandleGLES& handle) const { } std::optional ReactorGLES::GetGLFence(const HandleGLES& handle) const { - if (handle.type != HandleType::kFence) { + if (handle.GetType() != HandleType::kFence) { return std::nullopt; } std::optional gl_handle = GetHandle(handle); @@ -187,6 +191,7 @@ bool ReactorGLES::RegisterCleanupCallback(const HandleGLES& handle, if (handle.IsDead()) { return false; } + FML_DCHECK(!handle.untracked_id_.has_value()); WriterLock handles_lock(handles_mutex_); if (auto found = handles_.find(handle); found != handles_.end()) { found->second.callback = fml::ScopedCleanupClosure(callback); @@ -195,6 +200,17 @@ bool ReactorGLES::RegisterCleanupCallback(const HandleGLES& handle, return false; } +HandleGLES ReactorGLES::CreateUntrackedHandle(HandleType type) { + FML_DCHECK(CanReactOnCurrentThread()); + auto new_handle = HandleGLES::Create(type); + std::optional gl_handle = + CreateGLHandle(GetProcTable(), type); + if (gl_handle.has_value()) { + new_handle.untracked_id_ = gl_handle.value().integer; + } + return new_handle; +} + HandleGLES ReactorGLES::CreateHandle(HandleType type, GLuint external_handle) { if (type == HandleType::kUnknown) { return HandleGLES::DeadHandle(); @@ -203,7 +219,6 @@ HandleGLES ReactorGLES::CreateHandle(HandleType type, GLuint external_handle) { if (new_handle.IsDead()) { return HandleGLES::DeadHandle(); } - WriterLock handles_lock(handles_mutex_); std::optional gl_handle; if (external_handle != GL_NONE) { @@ -211,14 +226,26 @@ HandleGLES ReactorGLES::CreateHandle(HandleType type, GLuint external_handle) { } else if (CanReactOnCurrentThread()) { gl_handle = CreateGLHandle(GetProcTable(), type); } + + WriterLock handles_lock(handles_mutex_); handles_[new_handle] = LiveHandle{gl_handle}; return new_handle; } void ReactorGLES::CollectHandle(HandleGLES handle) { - WriterLock handles_lock(handles_mutex_); - if (auto found = handles_.find(handle); found != handles_.end()) { - found->second.pending_collection = true; + if (handle.untracked_id_.has_value()) { + LiveHandle live_handle(GLStorage{.integer = handle.untracked_id_.value()}); + live_handle.pending_collection = true; + WriterLock handles_lock(handles_mutex_); + handles_[handle] = std::move(live_handle); + } else { + WriterLock handles_lock(handles_mutex_); + if (auto found = handles_.find(handle); found != handles_.end()) { + if (!found->second.pending_collection) { + handles_to_collect_count_ += 1; + } + found->second.pending_collection = true; + } } } @@ -266,41 +293,58 @@ bool ReactorGLES::ReactOnce() { bool ReactorGLES::ConsolidateHandles() { TRACE_EVENT0("impeller", __FUNCTION__); const auto& gl = GetProcTable(); - WriterLock handles_lock(handles_mutex_); - std::vector handles_to_delete; - for (auto& handle : handles_) { - // Collect dead handles. - if (handle.second.pending_collection) { - // This could be false if the handle was created and collected without - // use. We still need to get rid of map entry. - if (handle.second.name.has_value()) { - CollectGLHandle(gl, handle.first.type, handle.second.name.value()); + std::vector>> + handles_to_delete; + std::vector> + handles_to_name; + { + WriterLock handles_lock(handles_mutex_); + handles_to_delete.reserve(handles_to_collect_count_); + handles_to_collect_count_ = 0; + for (auto& handle : handles_) { + // Collect dead handles. + if (handle.second.pending_collection) { + handles_to_delete.emplace_back( + std::make_tuple(handle.first, handle.second.name)); + continue; } - handles_to_delete.push_back(handle.first); - continue; - } - // Create live handles. - if (!handle.second.name.has_value()) { - auto gl_handle = CreateGLHandle(gl, handle.first.type); - if (!gl_handle) { - VALIDATION_LOG << "Could not create GL handle."; - return false; + // Create live handles. + if (!handle.second.name.has_value()) { + auto gl_handle = CreateGLHandle(gl, handle.first.GetType()); + if (!gl_handle) { + VALIDATION_LOG << "Could not create GL handle."; + return false; + } + handle.second.name = gl_handle; } - handle.second.name = gl_handle; - } - // Set pending debug labels. - if (handle.second.pending_debug_label.has_value() && - handle.first.type != HandleType::kFence) { - if (gl.SetDebugLabel(ToDebugResourceType(handle.first.type), - handle.second.name.value().handle, - handle.second.pending_debug_label.value())) { + // Set pending debug labels. + if (handle.second.pending_debug_label.has_value() && + handle.first.GetType() != HandleType::kFence) { + handles_to_name.emplace_back(std::make_tuple( + ToDebugResourceType(handle.first.GetType()), + handle.second.name.value().handle, + std::move(handle.second.pending_debug_label.value()))); handle.second.pending_debug_label = std::nullopt; } } + for (const auto& handle_to_delete : handles_to_delete) { + handles_.erase(std::get<0>(handle_to_delete)); + } } - for (const auto& handle_to_delete : handles_to_delete) { - handles_.erase(handle_to_delete); + + for (const auto& handle : handles_to_name) { + gl.SetDebugLabel(std::get<0>(handle), std::get<1>(handle), + std::get<2>(handle)); + } + for (const auto& handle : handles_to_delete) { + const std::optional& storage = std::get<1>(handle); + // This could be false if the handle was created and collected without + // use. We still need to get rid of map entry. + if (storage.has_value()) { + CollectGLHandle(gl, std::get<0>(handle).GetType(), storage.value()); + } } + return true; } @@ -342,15 +386,23 @@ void ReactorGLES::SetupDebugGroups() { void ReactorGLES::SetDebugLabel(const HandleGLES& handle, std::string_view label) { + FML_DCHECK(handle.GetType() != HandleType::kFence); if (!can_set_debug_labels_) { return; } if (handle.IsDead()) { return; } - WriterLock handles_lock(handles_mutex_); - if (auto found = handles_.find(handle); found != handles_.end()) { - found->second.pending_debug_label = label; + if (handle.untracked_id_.has_value()) { + FML_DCHECK(CanReactOnCurrentThread()); + const auto& gl = GetProcTable(); + gl.SetDebugLabel(ToDebugResourceType(handle.GetType()), + handle.untracked_id_.value(), label); + } else { + WriterLock handles_lock(handles_mutex_); + if (auto found = handles_.find(handle); found != handles_.end()) { + 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 88d77ccffe398..a05dd22b8fb42 100644 --- a/impeller/renderer/backend/gles/reactor_gles.h +++ b/impeller/renderer/backend/gles/reactor_gles.h @@ -9,6 +9,7 @@ #include #include +#include "flutter/third_party/abseil-cpp/absl/container/flat_hash_map.h" #include "fml/closure.h" #include "impeller/base/thread.h" #include "impeller/renderer/backend/gles/handle_gles.h" @@ -84,8 +85,6 @@ class ReactorGLES { const ReactorGLES& reactor) const = 0; }; - using Ref = std::shared_ptr; - //---------------------------------------------------------------------------- /// @brief Create a new reactor. There are expensive and only one per /// application instance is necessary. @@ -173,6 +172,16 @@ class ReactorGLES { /// HandleGLES CreateHandle(HandleType type, GLuint external_handle = GL_NONE); + /// @brief Create a handle that is not managed by `ReactorGLES`. + /// @details This behaves just like `CreateHandle` but it doesn't add the + /// handle to ReactorGLES::handles_ and the creation is executed + /// synchronously, so it must be called from a proper thread. The benefit of + /// this is that it avoid synchronization and hash table lookups when + /// creating/accessing the handle. + /// @param type The type of handle to create. + /// @return The reactor handle. + HandleGLES CreateUntrackedHandle(HandleType type); + //---------------------------------------------------------------------------- /// @brief Collect a reactor handle. /// @@ -254,8 +263,10 @@ class ReactorGLES { union { GLuint handle; GLsync sync; + uint64_t integer; }; }; + static_assert(sizeof(GLStorage) == sizeof(uint64_t)); struct LiveHandle { std::optional name; @@ -276,14 +287,13 @@ class ReactorGLES { std::map> ops_ IPLR_GUARDED_BY( ops_mutex_); - // Make sure the container is one where erasing items during iteration doesn't - // invalidate other iterators. - using LiveHandles = std::unordered_map; + using LiveHandles = absl::flat_hash_map; mutable RWMutex handles_mutex_; LiveHandles handles_ IPLR_GUARDED_BY(handles_mutex_); + int32_t handles_to_collect_count_ IPLR_GUARDED_BY(handles_mutex_) = 0; mutable Mutex workers_mutex_; mutable std::map> workers_ IPLR_GUARDED_BY( diff --git a/impeller/renderer/backend/gles/render_pass_gles.cc b/impeller/renderer/backend/gles/render_pass_gles.cc index 594fcfab0732f..c8900d6e0c1c0 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/impeller/renderer/backend/gles/render_pass_gles.cc @@ -6,23 +6,26 @@ #include -#include "GLES3/gl3.h" #include "flutter/fml/trace_event.h" #include "fml/closure.h" #include "fml/logging.h" #include "impeller/base/validation.h" +#include "impeller/core/buffer_view.h" +#include "impeller/core/formats.h" +#include "impeller/renderer/backend/gles/buffer_bindings_gles.h" #include "impeller/renderer/backend/gles/context_gles.h" #include "impeller/renderer/backend/gles/device_buffer_gles.h" #include "impeller/renderer/backend/gles/formats_gles.h" #include "impeller/renderer/backend/gles/gpu_tracer_gles.h" #include "impeller/renderer/backend/gles/pipeline_gles.h" #include "impeller/renderer/backend/gles/texture_gles.h" +#include "impeller/renderer/command.h" namespace impeller { RenderPassGLES::RenderPassGLES(std::shared_ptr context, const RenderTarget& target, - ReactorGLES::Ref reactor) + std::shared_ptr reactor) : RenderPass(std::move(context), target), reactor_(std::move(reactor)), is_valid_(reactor_ && reactor_->IsValid()) {} @@ -187,16 +190,17 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { [[nodiscard]] bool EncodeCommandsInReactor( const RenderPassData& pass_data, - const std::shared_ptr& transients_allocator, const ReactorGLES& reactor, const std::vector& commands, + const std::vector& vertex_buffers, + const std::vector& bound_textures, + const std::vector& bound_buffers, const std::shared_ptr& tracer) { TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor"); const auto& gl = reactor.GetProcTable(); #ifdef IMPELLER_DEBUG tracer->MarkFrameStart(gl); -#endif // IMPELLER_DEBUG fml::ScopedCleanupClosure pop_pass_debug_marker( [&gl]() { gl.PopDebugGroup(); }); @@ -205,6 +209,7 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { } else { pop_pass_debug_marker.Release(); } +#endif // IMPELLER_DEBUG GLuint fbo = GL_NONE; TextureGLES& color_gles = TextureGLES::Cast(*pass_data.color_attachment); @@ -217,7 +222,7 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { } } else { // Create and bind an offscreen FBO. - auto cached_fbo = color_gles.GetCachedFBO(); + GLuint cached_fbo = color_gles.GetCachedFBO(); if (cached_fbo != GL_NONE) { fbo = cached_fbo; gl.BindFramebuffer(GL_FRAMEBUFFER, fbo); @@ -285,17 +290,34 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { gl.Clear(clear_bits); - for (const auto& command : commands) { - if (command.instance_count != 1u) { - VALIDATION_LOG << "GLES backend does not support instanced rendering."; - return false; - } + // Both the viewport and scissor are specified in framebuffer coordinates. + // Impeller's framebuffer coordinate system is top left origin, but OpenGL's + // is bottom left origin, so we convert the coordinates here. + ISize target_size = pass_data.color_attachment->GetSize(); - if (!command.pipeline) { - VALIDATION_LOG << "Command has no pipeline specified."; - return false; + //-------------------------------------------------------------------------- + /// Setup the viewport. + /// + const auto& viewport = pass_data.viewport; + gl.Viewport(viewport.rect.GetX(), // x + target_size.height - viewport.rect.GetY() - + viewport.rect.GetHeight(), // y + viewport.rect.GetWidth(), // width + viewport.rect.GetHeight() // height + ); + if (pass_data.depth_attachment) { + if (gl.DepthRangef.IsAvailable()) { + gl.DepthRangef(viewport.depth_range.z_near, viewport.depth_range.z_far); + } else { + gl.DepthRange(viewport.depth_range.z_near, viewport.depth_range.z_far); } + } + + CullMode current_cull_mode = CullMode::kNone; + WindingOrder current_winding_order = WindingOrder::kClockwise; + gl.FrontFace(GL_CW); + for (const auto& command : commands) { #ifdef IMPELLER_DEBUG fml::ScopedCleanupClosure pop_cmd_debug_marker( [&gl]() { gl.PopDebugGroup(); }); @@ -339,26 +361,24 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { gl.Disable(GL_DEPTH_TEST); } - // Both the viewport and scissor are specified in framebuffer coordinates. - // Impeller's framebuffer coordinate system is top left origin, but OpenGL's - // is bottom left origin, so we convert the coordinates here. - auto target_size = pass_data.color_attachment->GetSize(); - //-------------------------------------------------------------------------- /// Setup the viewport. /// - const auto& viewport = command.viewport.value_or(pass_data.viewport); - gl.Viewport(viewport.rect.GetX(), // x - target_size.height - viewport.rect.GetY() - - viewport.rect.GetHeight(), // y - viewport.rect.GetWidth(), // width - viewport.rect.GetHeight() // height - ); - if (pass_data.depth_attachment) { - if (gl.DepthRangef.IsAvailable()) { - gl.DepthRangef(viewport.depth_range.z_near, viewport.depth_range.z_far); - } else { - gl.DepthRange(viewport.depth_range.z_near, viewport.depth_range.z_far); + if (command.viewport.has_value()) { + gl.Viewport(viewport.rect.GetX(), // x + target_size.height - viewport.rect.GetY() - + viewport.rect.GetHeight(), // y + viewport.rect.GetWidth(), // width + viewport.rect.GetHeight() // height + ); + if (pass_data.depth_attachment) { + if (gl.DepthRangef.IsAvailable()) { + gl.DepthRangef(viewport.depth_range.z_near, + viewport.depth_range.z_far); + } else { + gl.DepthRange(viewport.depth_range.z_near, + viewport.depth_range.z_far); + } } } @@ -379,36 +399,42 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { //-------------------------------------------------------------------------- /// Setup culling. /// - switch (pipeline.GetDescriptor().GetCullMode()) { - case CullMode::kNone: - gl.Disable(GL_CULL_FACE); - break; - case CullMode::kFrontFace: - gl.Enable(GL_CULL_FACE); - gl.CullFace(GL_FRONT); - break; - case CullMode::kBackFace: - gl.Enable(GL_CULL_FACE); - gl.CullFace(GL_BACK); - break; + CullMode pipeline_cull_mode = pipeline.GetDescriptor().GetCullMode(); + if (current_cull_mode != pipeline_cull_mode) { + switch (pipeline_cull_mode) { + case CullMode::kNone: + gl.Disable(GL_CULL_FACE); + break; + case CullMode::kFrontFace: + gl.Enable(GL_CULL_FACE); + gl.CullFace(GL_FRONT); + break; + case CullMode::kBackFace: + gl.Enable(GL_CULL_FACE); + gl.CullFace(GL_BACK); + break; + } + current_cull_mode = pipeline_cull_mode; } + //-------------------------------------------------------------------------- /// Setup winding order. /// - switch (pipeline.GetDescriptor().GetWindingOrder()) { - case WindingOrder::kClockwise: - gl.FrontFace(GL_CW); - break; - case WindingOrder::kCounterClockwise: - gl.FrontFace(GL_CCW); - break; + WindingOrder pipeline_winding_order = + pipeline.GetDescriptor().GetWindingOrder(); + if (current_winding_order != pipeline_winding_order) { + switch (pipeline.GetDescriptor().GetWindingOrder()) { + case WindingOrder::kClockwise: + gl.FrontFace(GL_CW); + break; + case WindingOrder::kCounterClockwise: + gl.FrontFace(GL_CCW); + break; + } + current_winding_order = pipeline_winding_order; } - auto vertex_desc_gles = pipeline.GetBufferBindings(); - - if (command.index_type == IndexType::kUnknown) { - return false; - } + BufferBindingsGLES* vertex_desc_gles = pipeline.GetBufferBindings(); //-------------------------------------------------------------------------- /// Bind vertex buffers. @@ -417,8 +443,9 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { /// `RenderPass::ValidateIndexBuffer` here, as validation already runs /// when the vertex/index buffers are set on the command. /// - for (size_t i = 0; i < command.vertex_buffer_count; i++) { - if (!BindVertexBuffer(gl, vertex_desc_gles, command.vertex_buffers[i], + for (size_t i = 0; i < command.vertex_buffers.length; i++) { + if (!BindVertexBuffer(gl, vertex_desc_gles, + vertex_buffers[i + command.vertex_buffers.offset], i)) { return false; } @@ -434,11 +461,13 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { //-------------------------------------------------------------------------- /// Bind uniform data. /// - if (!vertex_desc_gles->BindUniformData(gl, // - *transients_allocator, // - command.vertex_bindings, // - command.fragment_bindings // - )) { + if (!vertex_desc_gles->BindUniformData( + gl, // + bound_textures, // + bound_buffers, // + /*texture_range=*/command.bound_textures, // + /*buffer_range=*/command.bound_buffers // + )) { return false; } @@ -450,9 +479,10 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { // correct; full triangle outlines won't be drawn and disconnected // geometry may appear connected. However this can still be useful for // wireframe debug views. - auto mode = pipeline.GetDescriptor().GetPolygonMode() == PolygonMode::kLine - ? GL_LINE_STRIP - : ToMode(pipeline.GetDescriptor().GetPrimitiveType()); + GLenum mode = + pipeline.GetDescriptor().GetPolygonMode() == PolygonMode::kLine + ? GL_LINE_STRIP + : ToMode(pipeline.GetDescriptor().GetPrimitiveType()); //-------------------------------------------------------------------------- /// Finally! Invoke the draw call. @@ -482,13 +512,6 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { if (!vertex_desc_gles->UnbindVertexAttributes(gl)) { return false; } - - //-------------------------------------------------------------------------- - /// Unbind the program pipeline. - /// - if (!pipeline.UnbindProgram()) { - return false; - } } if (gl.DiscardFramebufferEXT.IsAvailable()) { @@ -537,9 +560,11 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const { if (!render_target.HasColorAttachment(0u)) { return false; } - const auto& color0 = render_target.GetColorAttachments().at(0u); - const auto& depth0 = render_target.GetDepthAttachment(); - const auto& stencil0 = render_target.GetStencilAttachment(); + const ColorAttachment& color0 = render_target.GetColorAttachment(0); + const std::optional& depth0 = + render_target.GetDepthAttachment(); + const std::optional& stencil0 = + render_target.GetStencilAttachment(); auto pass_data = std::make_shared(); pass_data->label = label_; @@ -585,13 +610,19 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const { CanDiscardAttachmentWhenDone(stencil0->store_action); } - std::shared_ptr shared_this = shared_from_this(); - auto tracer = ContextGLES::Cast(context).GetGPUTracer(); return reactor_->AddOperation( - [pass_data, allocator = context.GetResourceAllocator(), - render_pass = std::move(shared_this), tracer](const auto& reactor) { - auto result = EncodeCommandsInReactor(*pass_data, allocator, reactor, - render_pass->commands_, tracer); + [pass_data = std::move(pass_data), render_pass = shared_from_this(), + tracer = + ContextGLES::Cast(context).GetGPUTracer()](const auto& reactor) { + auto result = EncodeCommandsInReactor( + /*pass_data=*/*pass_data, // + /*reactor=*/reactor, // + /*commands=*/render_pass->commands_, // + /*vertex_buffers=*/render_pass->vertex_buffers_, // + /*bound_textures=*/render_pass->bound_textures_, // + /*bound_buffers=*/render_pass->bound_buffers_, // + /*tracer=*/tracer // + ); FML_CHECK(result) << "Must be able to encode GL commands without error."; }, diff --git a/impeller/renderer/backend/gles/render_pass_gles.h b/impeller/renderer/backend/gles/render_pass_gles.h index c0bd9e63e6cef..1d524fdc490a1 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.h +++ b/impeller/renderer/backend/gles/render_pass_gles.h @@ -24,13 +24,13 @@ class RenderPassGLES final private: friend class CommandBufferGLES; - ReactorGLES::Ref reactor_; + std::shared_ptr reactor_; std::string label_; bool is_valid_ = false; RenderPassGLES(std::shared_ptr context, const RenderTarget& target, - ReactorGLES::Ref reactor); + std::shared_ptr reactor); // |RenderPass| bool IsValid() const override; diff --git a/impeller/renderer/backend/gles/shader_library_gles.cc b/impeller/renderer/backend/gles/shader_library_gles.cc index 3c8dbbb816dac..018fc50c6b321 100644 --- a/impeller/renderer/backend/gles/shader_library_gles.cc +++ b/impeller/renderer/backend/gles/shader_library_gles.cc @@ -57,7 +57,6 @@ ShaderLibraryGLES::ShaderLibraryGLES( ) -> bool { const auto stage = ToShaderStage(type); const auto key_name = GLESShaderNameToShaderKeyName(name, stage); - functions[ShaderKey{key_name, stage}] = std::shared_ptr( new ShaderFunctionGLES(library_id, // stage, // diff --git a/impeller/renderer/backend/gles/test/capabilities_unittests.cc b/impeller/renderer/backend/gles/test/capabilities_unittests.cc index f93eab8605635..b0e69464cabbe 100644 --- a/impeller/renderer/backend/gles/test/capabilities_unittests.cc +++ b/impeller/renderer/backend/gles/test/capabilities_unittests.cc @@ -33,9 +33,9 @@ TEST(CapabilitiesGLES, CanInitializeWithDefaults) { } TEST(CapabilitiesGLES, SupportsDecalSamplerAddressMode) { - auto const extensions = std::vector{ - reinterpret_cast("GL_KHR_debug"), // - reinterpret_cast("GL_EXT_texture_border_clamp"), // + auto const extensions = std::vector{ + "GL_KHR_debug", // + "GL_EXT_texture_border_clamp", // }; auto mock_gles = MockGLES::Init(extensions); auto capabilities = mock_gles->GetProcTable().GetCapabilities(); @@ -43,9 +43,9 @@ TEST(CapabilitiesGLES, SupportsDecalSamplerAddressMode) { } TEST(CapabilitiesGLES, SupportsDecalSamplerAddressModeNotOES) { - auto const extensions = std::vector{ - reinterpret_cast("GL_KHR_debug"), // - reinterpret_cast("GL_OES_texture_border_clamp"), // + auto const extensions = std::vector{ + "GL_KHR_debug", // + "GL_OES_texture_border_clamp", // }; auto mock_gles = MockGLES::Init(extensions); auto capabilities = mock_gles->GetProcTable().GetCapabilities(); @@ -53,15 +53,24 @@ TEST(CapabilitiesGLES, SupportsDecalSamplerAddressModeNotOES) { } TEST(CapabilitiesGLES, SupportsFramebufferFetch) { - auto const extensions = std::vector{ - reinterpret_cast("GL_KHR_debug"), // - reinterpret_cast( - "GL_EXT_shader_framebuffer_fetch"), // + auto const extensions = std::vector{ + "GL_KHR_debug", // + "GL_EXT_shader_framebuffer_fetch", // }; auto mock_gles = MockGLES::Init(extensions); auto capabilities = mock_gles->GetProcTable().GetCapabilities(); EXPECT_TRUE(capabilities->SupportsFramebufferFetch()); } +TEST(CapabilitiesGLES, SupportsMSAA) { + auto const extensions = std::vector{ + "GL_EXT_multisampled_render_to_texture", + }; + auto mock_gles = MockGLES::Init(extensions); + auto capabilities = mock_gles->GetProcTable().GetCapabilities(); + EXPECT_TRUE(capabilities->SupportsImplicitResolvingMSAA()); + EXPECT_FALSE(capabilities->SupportsOffscreenMSAA()); +} + } // namespace testing } // namespace impeller diff --git a/impeller/renderer/backend/gles/test/gpu_tracer_gles_unittests.cc b/impeller/renderer/backend/gles/test/gpu_tracer_gles_unittests.cc index d0579a2091b23..2ee1da6c1b386 100644 --- a/impeller/renderer/backend/gles/test/gpu_tracer_gles_unittests.cc +++ b/impeller/renderer/backend/gles/test/gpu_tracer_gles_unittests.cc @@ -10,38 +10,48 @@ namespace impeller { namespace testing { +using ::testing::_; + #ifdef IMPELLER_DEBUG TEST(GPUTracerGLES, CanFormatFramebufferErrorMessage) { - auto const extensions = std::vector{ - reinterpret_cast("GL_KHR_debug"), // - reinterpret_cast("GL_EXT_disjoint_timer_query"), // + auto const extensions = std::vector{ + "GL_KHR_debug", // + "GL_EXT_disjoint_timer_query", // }; - auto mock_gles = MockGLES::Init(extensions); + auto mock_gles_impl = std::make_unique(); + + { + ::testing::InSequence seq; + auto gen_queries = [](GLsizei n, GLuint* ids) { + for (int i = 0; i < n; ++i) { + ids[i] = i + 1; + } + }; + EXPECT_CALL(*mock_gles_impl, GenQueriesEXT(_, _)).WillOnce(gen_queries); + EXPECT_CALL(*mock_gles_impl, BeginQueryEXT(GL_TIME_ELAPSED_EXT, _)); + EXPECT_CALL(*mock_gles_impl, EndQueryEXT(GL_TIME_ELAPSED_EXT)); + EXPECT_CALL(*mock_gles_impl, + GetQueryObjectuivEXT(_, GL_QUERY_RESULT_AVAILABLE_EXT, _)) + .WillOnce([](GLuint id, GLenum target, GLuint* result) { + *result = GL_TRUE; + }); + EXPECT_CALL(*mock_gles_impl, + GetQueryObjectui64vEXT(_, GL_QUERY_RESULT_EXT, _)) + .WillOnce([](GLuint id, GLenum target, GLuint64* result) { + *result = 1000u; + }); + EXPECT_CALL(*mock_gles_impl, DeleteQueriesEXT(_, _)); + EXPECT_CALL(*mock_gles_impl, GenQueriesEXT(_, _)).WillOnce(gen_queries); + EXPECT_CALL(*mock_gles_impl, BeginQueryEXT(GL_TIME_ELAPSED_EXT, _)); + } + std::shared_ptr mock_gles = + MockGLES::Init(std::move(mock_gles_impl), extensions); auto tracer = std::make_shared(mock_gles->GetProcTable(), true); tracer->RecordRasterThread(); tracer->MarkFrameStart(mock_gles->GetProcTable()); tracer->MarkFrameEnd(mock_gles->GetProcTable()); - - auto calls = mock_gles->GetCapturedCalls(); - - std::vector expected = {"glGenQueriesEXT", "glBeginQueryEXT", - "glEndQueryEXT"}; - for (auto i = 0; i < 3; i++) { - EXPECT_EQ(calls[i], expected[i]); - } - - // Begin second frame, which prompts the tracer to query the result - // from the previous frame. tracer->MarkFrameStart(mock_gles->GetProcTable()); - - calls = mock_gles->GetCapturedCalls(); - std::vector expected_b = {"glGetQueryObjectuivEXT", - "glGetQueryObjectui64vEXT", - "glDeleteQueriesEXT"}; - for (auto i = 0; i < 3; i++) { - EXPECT_EQ(calls[i], expected_b[i]); - } } #endif // IMPELLER_DEBUG diff --git a/impeller/renderer/backend/gles/test/mock_gles.cc b/impeller/renderer/backend/gles/test/mock_gles.cc index 7a8399cede36c..c62ff4fe71483 100644 --- a/impeller/renderer/backend/gles/test/mock_gles.cc +++ b/impeller/renderer/backend/gles/test/mock_gles.cc @@ -19,18 +19,9 @@ static std::mutex g_test_lock; static std::weak_ptr g_mock_gles; -static ProcTableGLES::Resolver g_resolver; +static std::vector g_extensions; -static std::vector g_extensions; - -static const unsigned char* g_version; - -// Has friend visibility into MockGLES to record calls. -void RecordGLCall(const char* name) { - if (auto mock_gles = g_mock_gles.lock()) { - mock_gles->RecordCall(name); - } -} +static const char* g_version; template struct CheckSameSignature : std::false_type {}; @@ -41,22 +32,34 @@ struct CheckSameSignature : std::true_type {}; // This is a stub function that does nothing/records nothing. void doNothing() {} -auto const kMockVendor = (unsigned char*)"MockGLES"; -const auto kMockShadingLanguageVersion = (unsigned char*)"GLSL ES 1.0"; -auto const kExtensions = std::vector{ - (unsigned char*)"GL_KHR_debug" // +auto const kMockVendor = "MockGLES"; +const auto kMockShadingLanguageVersion = "GLSL ES 1.0"; +auto const kExtensions = std::vector{ + "GL_KHR_debug" // }; +namespace { +template +void CallMockMethod(Func func, Args&&... args) { + if (auto mock_gles = g_mock_gles.lock()) { + if (mock_gles->GetImpl()) { + (mock_gles->GetImpl()->*func)(std::forward(args)...); + } + } +} +} // namespace + const unsigned char* mockGetString(GLenum name) { switch (name) { case GL_VENDOR: - return kMockVendor; + return reinterpret_cast(kMockVendor); case GL_VERSION: - return g_version; + return reinterpret_cast(g_version); case GL_SHADING_LANGUAGE_VERSION: - return kMockShadingLanguageVersion; + return reinterpret_cast( + kMockShadingLanguageVersion); default: - return (unsigned char*)""; + return reinterpret_cast(""); } } @@ -66,9 +69,9 @@ static_assert(CheckSameSignature(g_extensions[index]); default: - return (unsigned char*)""; + return reinterpret_cast(""); } } @@ -83,6 +86,9 @@ void mockGetIntegerv(GLenum name, int* value) { case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *value = 8; break; + case GL_MAX_LABEL_LENGTH_KHR: + *value = 64; + break; default: *value = 0; break; @@ -99,9 +105,7 @@ GLenum mockGetError() { static_assert(CheckSameSignature::value); -void mockPopDebugGroupKHR() { - RecordGLCall("PopDebugGroupKHR"); -} +void mockPopDebugGroupKHR() {} static_assert(CheckSameSignature::value); @@ -109,73 +113,110 @@ static_assert(CheckSameSignature::value); void mockGenQueriesEXT(GLsizei n, GLuint* ids) { - RecordGLCall("glGenQueriesEXT"); - for (auto i = 0; i < n; i++) { - ids[i] = i + 1; - } + CallMockMethod(&IMockGLESImpl::GenQueriesEXT, n, ids); } static_assert(CheckSameSignature::value); void mockBeginQueryEXT(GLenum target, GLuint id) { - RecordGLCall("glBeginQueryEXT"); + CallMockMethod(&IMockGLESImpl::BeginQueryEXT, target, id); } static_assert(CheckSameSignature::value); void mockEndQueryEXT(GLuint id) { - RecordGLCall("glEndQueryEXT"); + CallMockMethod(&IMockGLESImpl::EndQueryEXT, id); } static_assert(CheckSameSignature::value); void mockGetQueryObjectuivEXT(GLuint id, GLenum target, GLuint* result) { - RecordGLCall("glGetQueryObjectuivEXT"); - *result = GL_TRUE; + CallMockMethod(&IMockGLESImpl::GetQueryObjectuivEXT, id, target, result); } static_assert(CheckSameSignature::value); void mockGetQueryObjectui64vEXT(GLuint id, GLenum target, GLuint64* result) { - RecordGLCall("glGetQueryObjectui64vEXT"); - *result = 1000u; + CallMockMethod(&IMockGLESImpl::GetQueryObjectui64vEXT, id, target, result); } static_assert(CheckSameSignature::value); void mockDeleteQueriesEXT(GLsizei size, const GLuint* queries) { - RecordGLCall("glDeleteQueriesEXT"); + CallMockMethod(&IMockGLESImpl::DeleteQueriesEXT, size, queries); } void mockDeleteTextures(GLsizei size, const GLuint* queries) { - RecordGLCall("glDeleteTextures"); + CallMockMethod(&IMockGLESImpl::DeleteTextures, size, queries); } static_assert(CheckSameSignature::value); +void mockUniform1fv(GLint location, GLsizei count, const GLfloat* value) { + CallMockMethod(&IMockGLESImpl::Uniform1fv, location, count, value); +} +static_assert(CheckSameSignature::value); + +void mockGenTextures(GLsizei n, GLuint* textures) { + CallMockMethod(&IMockGLESImpl::GenTextures, n, textures); +} + +static_assert(CheckSameSignature::value); + +void mockGenBuffers(GLsizei n, GLuint* buffers) { + CallMockMethod(&IMockGLESImpl::GenBuffers, n, buffers); +} + +static_assert(CheckSameSignature::value); + +void mockObjectLabelKHR(GLenum identifier, + GLuint name, + GLsizei length, + const GLchar* label) { + CallMockMethod(&IMockGLESImpl::ObjectLabelKHR, identifier, name, length, + label); +} +static_assert(CheckSameSignature::value); + +// static +std::shared_ptr MockGLES::Init( + std::unique_ptr impl, + const std::optional>& extensions) { + FML_CHECK(g_test_lock.try_lock()) + << "MockGLES is already being used by another test."; + g_extensions = extensions.value_or(kExtensions); + g_version = "OpenGL ES 3.0"; + auto mock_gles = std::shared_ptr(new MockGLES()); + mock_gles->impl_ = std::move(impl); + g_mock_gles = mock_gles; + return mock_gles; +} + std::shared_ptr MockGLES::Init( - const std::optional>& extensions, + const std::optional>& extensions, const char* version_string, ProcTableGLES::Resolver resolver) { // If we cannot obtain a lock, MockGLES is already being used elsewhere. FML_CHECK(g_test_lock.try_lock()) << "MockGLES is already being used by another test."; - g_version = (unsigned char*)version_string; g_extensions = extensions.value_or(kExtensions); + g_version = version_string; auto mock_gles = std::shared_ptr(new MockGLES(std::move(resolver))); g_mock_gles = mock_gles; return mock_gles; @@ -208,6 +249,14 @@ const ProcTableGLES::Resolver kMockResolverGLES = [](const char* name) { return reinterpret_cast(mockGetQueryObjectui64vEXT); } else if (strcmp(name, "glGetQueryObjectuivEXT") == 0) { return reinterpret_cast(mockGetQueryObjectuivEXT); + } else if (strcmp(name, "glUniform1fv") == 0) { + return reinterpret_cast(mockUniform1fv); + } else if (strcmp(name, "glGenTextures") == 0) { + return reinterpret_cast(mockGenTextures); + } else if (strcmp(name, "glObjectLabelKHR") == 0) { + return reinterpret_cast(mockObjectLabelKHR); + } else if (strcmp(name, "glGenBuffers") == 0) { + return reinterpret_cast(mockGenBuffers); } else { return reinterpret_cast(&doNothing); } diff --git a/impeller/renderer/backend/gles/test/mock_gles.h b/impeller/renderer/backend/gles/test/mock_gles.h index 0ce2bcb6e31af..681b894ac410b 100644 --- a/impeller/renderer/backend/gles/test/mock_gles.h +++ b/impeller/renderer/backend/gles/test/mock_gles.h @@ -8,6 +8,7 @@ #include #include +#include "gmock/gmock.h" #include "impeller/renderer/backend/gles/proc_table_gles.h" namespace impeller { @@ -15,6 +16,62 @@ namespace testing { extern const ProcTableGLES::Resolver kMockResolverGLES; +class IMockGLESImpl { + public: + virtual ~IMockGLESImpl() = default; + virtual void DeleteTextures(GLsizei size, const GLuint* queries) {} + virtual void GenTextures(GLsizei n, GLuint* textures) {} + virtual void ObjectLabelKHR(GLenum identifier, + GLuint name, + GLsizei length, + const GLchar* label) {} + virtual void Uniform1fv(GLint location, GLsizei count, const GLfloat* value) { + } + virtual void GenQueriesEXT(GLsizei n, GLuint* ids) {} + virtual void BeginQueryEXT(GLenum target, GLuint id) {} + virtual void EndQueryEXT(GLuint id) {} + virtual void GetQueryObjectuivEXT(GLuint id, GLenum target, GLuint* result) {} + virtual void GetQueryObjectui64vEXT(GLuint id, + GLenum target, + GLuint64* result) {} + virtual void DeleteQueriesEXT(GLsizei size, const GLuint* queries) {} + virtual void GenBuffers(GLsizei n, GLuint* buffers) {} +}; + +class MockGLESImpl : public IMockGLESImpl { + public: + MOCK_METHOD(void, + DeleteTextures, + (GLsizei size, const GLuint* queries), + (override)); + MOCK_METHOD(void, GenTextures, (GLsizei n, GLuint* textures), (override)); + MOCK_METHOD( + void, + ObjectLabelKHR, + (GLenum identifier, GLuint name, GLsizei length, const GLchar* label), + (override)); + MOCK_METHOD(void, + Uniform1fv, + (GLint location, GLsizei count, const GLfloat* value), + (override)); + MOCK_METHOD(void, GenQueriesEXT, (GLsizei n, GLuint* ids), (override)); + MOCK_METHOD(void, BeginQueryEXT, (GLenum target, GLuint id), (override)); + MOCK_METHOD(void, EndQueryEXT, (GLuint id), (override)); + MOCK_METHOD(void, + GetQueryObjectuivEXT, + (GLuint id, GLenum target, GLuint* result), + (override)); + MOCK_METHOD(void, + GetQueryObjectui64vEXT, + (GLuint id, GLenum target, GLuint64* result), + (override)); + MOCK_METHOD(void, + DeleteQueriesEXT, + (GLsizei size, const GLuint* queries), + (override)); + MOCK_METHOD(void, GenBuffers, (GLsizei n, GLuint* buffers), (override)); +}; + /// @brief Provides a mocked version of the |ProcTableGLES| class. /// /// Typically, Open GLES at runtime will be provided the host's GLES bindings @@ -25,40 +82,35 @@ extern const ProcTableGLES::Resolver kMockResolverGLES; /// See `README.md` for more information. class MockGLES final { public: + static std::shared_ptr Init( + std::unique_ptr impl, + const std::optional>& extensions = std::nullopt); + /// @brief Returns an initialized |MockGLES| instance. /// /// This method overwrites mocked global GLES function pointers to record /// invocations on this instance of |MockGLES|. As such, it should only be /// called once per test. static std::shared_ptr Init( - const std::optional>& extensions = - std::nullopt, + const std::optional>& extensions = std::nullopt, const char* version_string = "OpenGL ES 3.0", ProcTableGLES::Resolver resolver = kMockResolverGLES); /// @brief Returns a configured |ProcTableGLES| instance. const ProcTableGLES& GetProcTable() const { return proc_table_; } - /// @brief Returns a vector of the names of all recorded calls. - /// - /// Calls are cleared after this method is called. - std::vector GetCapturedCalls() { - std::vector calls = captured_calls_; - captured_calls_.clear(); - return calls; - } - ~MockGLES(); + IMockGLESImpl* GetImpl() { return impl_.get(); } + private: friend void RecordGLCall(const char* name); + friend void mockGenTextures(GLsizei n, GLuint* textures); explicit MockGLES(ProcTableGLES::Resolver resolver = kMockResolverGLES); - void RecordCall(const char* name) { captured_calls_.emplace_back(name); } - ProcTableGLES proc_table_; - std::vector captured_calls_; + std::unique_ptr impl_; MockGLES(const MockGLES&) = delete; diff --git a/impeller/renderer/backend/gles/test/mock_gles_unittests.cc b/impeller/renderer/backend/gles/test/mock_gles_unittests.cc index 5345cdbd0054e..96dea6bffcbd9 100644 --- a/impeller/renderer/backend/gles/test/mock_gles_unittests.cc +++ b/impeller/renderer/backend/gles/test/mock_gles_unittests.cc @@ -21,19 +21,6 @@ TEST(MockGLES, CanInitialize) { EXPECT_EQ(vendor, "MockGLES"); } -// Tests we can call two functions and capture the calls. -TEST(MockGLES, CapturesPushAndPopDebugGroup) { - auto mock_gles = MockGLES::Init(); - - auto& gl = mock_gles->GetProcTable(); - gl.PushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 0, -1, "test"); - gl.PopDebugGroupKHR(); - - auto calls = mock_gles->GetCapturedCalls(); - EXPECT_EQ(calls, std::vector( - {"PushDebugGroupKHR", "PopDebugGroupKHR"})); -} - // Tests that if we call a function we have not mocked, it's OK. TEST(MockGLES, CanCallUnmockedFunction) { auto mock_gles = MockGLES::Init(); diff --git a/impeller/renderer/backend/gles/test/pipeline_library_gles_unittests.cc b/impeller/renderer/backend/gles/test/pipeline_library_gles_unittests.cc index 23d54c40ec272..34dcff509b7af 100644 --- a/impeller/renderer/backend/gles/test/pipeline_library_gles_unittests.cc +++ b/impeller/renderer/backend/gles/test/pipeline_library_gles_unittests.cc @@ -38,8 +38,8 @@ TEST_P(PipelineLibraryGLESTest, ProgramHandlesAreReused) { // The program handles should be live and equal. ASSERT_FALSE(pipeline_gles.GetProgramHandle().IsDead()); ASSERT_FALSE(new_pipeline_gles.GetProgramHandle().IsDead()); - ASSERT_EQ(pipeline_gles.GetProgramHandle().name.value(), - new_pipeline_gles.GetProgramHandle().name.value()); + ASSERT_EQ(pipeline_gles.GetProgramHandle().GetName().value(), + new_pipeline_gles.GetProgramHandle().GetName().value()); } TEST_P(PipelineLibraryGLESTest, ChangingSpecConstantsCausesNewProgramObject) { @@ -63,8 +63,8 @@ TEST_P(PipelineLibraryGLESTest, ChangingSpecConstantsCausesNewProgramObject) { // The program handles should be live and equal. ASSERT_FALSE(pipeline_gles.GetProgramHandle().IsDead()); ASSERT_FALSE(new_pipeline_gles.GetProgramHandle().IsDead()); - ASSERT_FALSE(pipeline_gles.GetProgramHandle().name.value() == - new_pipeline_gles.GetProgramHandle().name.value()); + ASSERT_FALSE(pipeline_gles.GetProgramHandle().GetName().value() == + new_pipeline_gles.GetProgramHandle().GetName().value()); } // NOLINTEND(bugprone-unchecked-optional-access) diff --git a/impeller/renderer/backend/gles/test/reactor_unittests.cc b/impeller/renderer/backend/gles/test/reactor_unittests.cc index c43b9b1b96c40..48ee45dd3a3be 100644 --- a/impeller/renderer/backend/gles/test/reactor_unittests.cc +++ b/impeller/renderer/backend/gles/test/reactor_unittests.cc @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #include #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/testing/testing.h" // IWYU pragma: keep +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "impeller/renderer/backend/gles/handle_gles.h" #include "impeller/renderer/backend/gles/proc_table_gles.h" @@ -14,6 +16,8 @@ namespace impeller { namespace testing { +using ::testing::_; + class TestWorker : public ReactorGLES::Worker { public: bool CanReactorReactOnCurrentThreadNow( @@ -45,20 +49,71 @@ TEST(ReactorGLES, CanAttachCleanupCallbacksToHandles) { } TEST(ReactorGLES, DeletesHandlesDuringShutdown) { - auto mock_gles = MockGLES::Init(); + auto mock_gles_impl = std::make_unique(); + + EXPECT_CALL(*mock_gles_impl, GenTextures(1, _)) + .WillOnce([](GLsizei size, GLuint* queries) { queries[0] = 1234; }); + EXPECT_CALL(*mock_gles_impl, DeleteTextures(1, ::testing::Pointee(1234))) + .Times(1); + + std::shared_ptr mock_gles = + MockGLES::Init(std::move(mock_gles_impl)); ProcTableGLES::Resolver resolver = kMockResolverGLES; auto proc_table = std::make_unique(resolver); auto worker = std::make_shared(); auto reactor = std::make_shared(std::move(proc_table)); reactor->AddWorker(worker); + reactor->CreateHandle(HandleType::kTexture); + reactor.reset(); +} - reactor->CreateHandle(HandleType::kTexture, 123); +TEST(ReactorGLES, UntrackedHandle) { + auto mock_gles_impl = std::make_unique(); - reactor.reset(); + EXPECT_CALL(*mock_gles_impl, GenTextures(1, _)) + .WillOnce([](GLsizei size, GLuint* queries) { queries[0] = 1234; }); + EXPECT_CALL(*mock_gles_impl, DeleteTextures(1, ::testing::Pointee(1234))) + .Times(1); + + std::shared_ptr mock_gles = + MockGLES::Init(std::move(mock_gles_impl)); + ProcTableGLES::Resolver resolver = kMockResolverGLES; + auto proc_table = std::make_unique(resolver); + auto worker = std::make_shared(); + auto reactor = std::make_shared(std::move(proc_table)); + reactor->AddWorker(worker); + + HandleGLES handle = reactor->CreateUntrackedHandle(HandleType::kTexture); + EXPECT_FALSE(handle.IsDead()); + std::optional glint = reactor->GetGLHandle(handle); + EXPECT_TRUE(glint.has_value()); + if (glint.has_value()) { + EXPECT_EQ(1234u, *glint); + } + reactor->CollectHandle(handle); + EXPECT_TRUE(reactor->AddOperation([&](const ReactorGLES&) {})); + EXPECT_TRUE(reactor->React()); +} + +TEST(ReactorGLES, NameUntrackedHandle) { + auto mock_gles_impl = std::make_unique(); + + EXPECT_CALL(*mock_gles_impl, GenTextures(1, _)) + .WillOnce([](GLsizei size, GLuint* queries) { queries[0] = 1234; }); + EXPECT_CALL(*mock_gles_impl, + ObjectLabelKHR(_, 1234, _, ::testing::StrEq("hello, joe!"))) + .Times(1); + + std::shared_ptr mock_gles = + MockGLES::Init(std::move(mock_gles_impl)); + ProcTableGLES::Resolver resolver = kMockResolverGLES; + auto proc_table = std::make_unique(resolver); + auto worker = std::make_shared(); + auto reactor = std::make_shared(std::move(proc_table)); + reactor->AddWorker(worker); - auto calls = mock_gles->GetCapturedCalls(); - EXPECT_TRUE(std::find(calls.begin(), calls.end(), "glDeleteTextures") != - calls.end()); + HandleGLES handle = reactor->CreateUntrackedHandle(HandleType::kTexture); + reactor->SetDebugLabel(handle, "hello, joe!"); } TEST(ReactorGLES, PerThreadOperationQueues) { diff --git a/impeller/renderer/backend/gles/test/surface_gles_unittests.cc b/impeller/renderer/backend/gles/test/surface_gles_unittests.cc index dbef03075a088..a039e03786c22 100644 --- a/impeller/renderer/backend/gles/test/surface_gles_unittests.cc +++ b/impeller/renderer/backend/gles/test/surface_gles_unittests.cc @@ -22,7 +22,7 @@ TEST_P(SurfaceGLESTest, CanWrapNonZeroFBO) { ASSERT_TRUE(surface->IsValid()); ASSERT_TRUE(surface->GetRenderTarget().HasColorAttachment(0)); const auto& texture = TextureGLES::Cast( - *(surface->GetRenderTarget().GetColorAttachments().at(0).texture)); + *(surface->GetRenderTarget().GetColorAttachment(0).texture)); auto wrapped = texture.GetFBO(); ASSERT_TRUE(wrapped.has_value()); // NOLINTNEXTLINE(bugprone-unchecked-optional-access) diff --git a/impeller/renderer/backend/gles/test/texture_gles_unittests.cc b/impeller/renderer/backend/gles/test/texture_gles_unittests.cc index ceafa3a2197e3..fd1797209a928 100644 --- a/impeller/renderer/backend/gles/test/texture_gles_unittests.cc +++ b/impeller/renderer/backend/gles/test/texture_gles_unittests.cc @@ -44,7 +44,7 @@ TEST_P(TextureGLESTest, CanSetSyncFence) { if (!sync_fence.has_value()) { return; } - EXPECT_EQ(sync_fence.value().type, HandleType::kFence); + EXPECT_EQ(sync_fence.value().GetType(), HandleType::kFence); std::optional sync = context_gles.GetReactor()->GetGLFence(sync_fence.value()); diff --git a/impeller/renderer/backend/gles/texture_gles.cc b/impeller/renderer/backend/gles/texture_gles.cc index 682e2cffd136a..e85aeb3772111 100644 --- a/impeller/renderer/backend/gles/texture_gles.cc +++ b/impeller/renderer/backend/gles/texture_gles.cc @@ -140,9 +140,10 @@ HandleType ToHandleType(TextureGLES::Type type) { FML_UNREACHABLE(); } -std::shared_ptr TextureGLES::WrapFBO(ReactorGLES::Ref reactor, - TextureDescriptor desc, - GLuint fbo) { +std::shared_ptr TextureGLES::WrapFBO( + std::shared_ptr reactor, + TextureDescriptor desc, + GLuint fbo) { auto texture = std::shared_ptr( new TextureGLES(std::move(reactor), desc, fbo, std::nullopt)); if (!texture->IsValid()) { @@ -152,14 +153,14 @@ std::shared_ptr TextureGLES::WrapFBO(ReactorGLES::Ref reactor, } std::shared_ptr TextureGLES::WrapTexture( - ReactorGLES::Ref reactor, + std::shared_ptr reactor, TextureDescriptor desc, HandleGLES external_handle) { if (external_handle.IsDead()) { VALIDATION_LOG << "Cannot wrap a dead handle."; return nullptr; } - if (external_handle.type != HandleType::kTexture) { + if (external_handle.GetType() != HandleType::kTexture) { VALIDATION_LOG << "Cannot wrap a non-texture handle."; return nullptr; } @@ -172,12 +173,13 @@ std::shared_ptr TextureGLES::WrapTexture( } std::shared_ptr TextureGLES::CreatePlaceholder( - ReactorGLES::Ref reactor, + std::shared_ptr reactor, TextureDescriptor desc) { return TextureGLES::WrapFBO(std::move(reactor), desc, 0u); } -TextureGLES::TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc) +TextureGLES::TextureGLES(std::shared_ptr reactor, + TextureDescriptor desc) : TextureGLES(std::move(reactor), // desc, // std::nullopt, // @@ -193,7 +195,7 @@ TextureGLES::TextureGLES(std::shared_ptr reactor, type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())), handle_(external_handle.has_value() ? external_handle.value() - : reactor_->CreateHandle(ToHandleType(type_))), + : reactor_->CreateUntrackedHandle(ToHandleType(type_))), is_wrapped_(fbo.has_value() || external_handle.has_value()), wrapped_fbo_(fbo) { // Ensure the texture descriptor itself is valid. @@ -407,7 +409,7 @@ void TextureGLES::InitializeContentsIfNecessary() const { } const auto& gl = reactor_->GetProcTable(); - auto handle = reactor_->GetGLHandle(handle_); + std::optional handle = reactor_->GetGLHandle(handle_); if (!handle.has_value()) { VALIDATION_LOG << "Could not initialize the contents of texture."; return; diff --git a/impeller/renderer/backend/gles/texture_gles.h b/impeller/renderer/backend/gles/texture_gles.h index 36f569379f70e..597fb726b21c7 100644 --- a/impeller/renderer/backend/gles/texture_gles.h +++ b/impeller/renderer/backend/gles/texture_gles.h @@ -39,9 +39,10 @@ class TextureGLES final : public Texture, /// @return If a texture representation of the framebuffer could be /// created. /// - static std::shared_ptr WrapFBO(ReactorGLES::Ref reactor, - TextureDescriptor desc, - GLuint fbo); + static std::shared_ptr WrapFBO( + std::shared_ptr reactor, + TextureDescriptor desc, + GLuint fbo); //---------------------------------------------------------------------------- /// @brief Create a texture by wrapping an external OpenGL texture @@ -55,9 +56,10 @@ class TextureGLES final : public Texture, /// @return If a texture representation of the framebuffer could be /// created. /// - static std::shared_ptr WrapTexture(ReactorGLES::Ref reactor, - TextureDescriptor desc, - HandleGLES external_handle); + static std::shared_ptr WrapTexture( + std::shared_ptr reactor, + TextureDescriptor desc, + HandleGLES external_handle); //---------------------------------------------------------------------------- /// @brief Create a "texture" that is never expected to be bound/unbound @@ -70,10 +72,10 @@ class TextureGLES final : public Texture, /// @return If a texture placeholder could be created. /// static std::shared_ptr CreatePlaceholder( - ReactorGLES::Ref reactor, + std::shared_ptr reactor, TextureDescriptor desc); - TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc); + TextureGLES(std::shared_ptr reactor, TextureDescriptor desc); // |Texture| ~TextureGLES() override; @@ -143,7 +145,7 @@ class TextureGLES final : public Texture, std::optional GetSyncFence() const; private: - ReactorGLES::Ref reactor_; + std::shared_ptr reactor_; const Type type_; HandleGLES handle_; mutable std::optional fence_ = std::nullopt; diff --git a/impeller/renderer/backend/gles/unique_handle_gles.cc b/impeller/renderer/backend/gles/unique_handle_gles.cc index ddf4081791672..d45dd4d79a550 100644 --- a/impeller/renderer/backend/gles/unique_handle_gles.cc +++ b/impeller/renderer/backend/gles/unique_handle_gles.cc @@ -8,14 +8,25 @@ namespace impeller { -UniqueHandleGLES::UniqueHandleGLES(ReactorGLES::Ref reactor, HandleType type) +UniqueHandleGLES::UniqueHandleGLES(std::shared_ptr reactor, + HandleType type) : reactor_(std::move(reactor)) { if (reactor_) { handle_ = reactor_->CreateHandle(type); } } -UniqueHandleGLES::UniqueHandleGLES(ReactorGLES::Ref reactor, HandleGLES handle) +// static +UniqueHandleGLES UniqueHandleGLES::MakeUntracked( + std::shared_ptr reactor, + HandleType type) { + FML_DCHECK(reactor); + HandleGLES handle = reactor->CreateUntrackedHandle(type); + return UniqueHandleGLES(std::move(reactor), handle); +} + +UniqueHandleGLES::UniqueHandleGLES(std::shared_ptr reactor, + HandleGLES handle) : reactor_(std::move(reactor)), handle_(handle) {} UniqueHandleGLES::~UniqueHandleGLES() { diff --git a/impeller/renderer/backend/gles/unique_handle_gles.h b/impeller/renderer/backend/gles/unique_handle_gles.h index 91c3bc2a67122..e5bbc33293bdc 100644 --- a/impeller/renderer/backend/gles/unique_handle_gles.h +++ b/impeller/renderer/backend/gles/unique_handle_gles.h @@ -17,9 +17,12 @@ namespace impeller { /// class UniqueHandleGLES { public: - UniqueHandleGLES(ReactorGLES::Ref reactor, HandleType type); + UniqueHandleGLES(std::shared_ptr reactor, HandleType type); - UniqueHandleGLES(ReactorGLES::Ref reactor, HandleGLES handle); + static UniqueHandleGLES MakeUntracked(std::shared_ptr reactor, + HandleType type); + + UniqueHandleGLES(std::shared_ptr reactor, HandleGLES handle); ~UniqueHandleGLES(); @@ -34,7 +37,7 @@ class UniqueHandleGLES { bool IsValid() const; private: - ReactorGLES::Ref reactor_ = nullptr; + std::shared_ptr reactor_ = nullptr; HandleGLES handle_ = HandleGLES::DeadHandle(); }; diff --git a/impeller/renderer/backend/gles/unique_handle_gles_unittests.cc b/impeller/renderer/backend/gles/unique_handle_gles_unittests.cc new file mode 100644 index 0000000000000..01ddf037f1187 --- /dev/null +++ b/impeller/renderer/backend/gles/unique_handle_gles_unittests.cc @@ -0,0 +1,45 @@ +// 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/testing/testing.h" // IWYU pragma: keep +#include "gtest/gtest.h" +#include "impeller/renderer/backend/gles/reactor_gles.h" +#include "impeller/renderer/backend/gles/test/mock_gles.h" +#include "impeller/renderer/backend/gles/unique_handle_gles.h" + +namespace impeller { +namespace testing { + +using ::testing::_; + +namespace { +class TestWorker : public ReactorGLES::Worker { + public: + bool CanReactorReactOnCurrentThreadNow( + const ReactorGLES& reactor) const override { + return true; + } +}; +} // namespace + +TEST(UniqueHandleGLES, MakeUntracked) { + auto mock_gles_impl = std::make_unique(); + + EXPECT_CALL(*mock_gles_impl, GenTextures(1, _)).Times(1); + + std::shared_ptr mock_gled = + MockGLES::Init(std::move(mock_gles_impl)); + ProcTableGLES::Resolver resolver = kMockResolverGLES; + auto proc_table = std::make_unique(resolver); + auto worker = std::make_shared(); + auto reactor = std::make_shared(std::move(proc_table)); + reactor->AddWorker(worker); + + UniqueHandleGLES handle = + UniqueHandleGLES::MakeUntracked(reactor, HandleType::kTexture); + EXPECT_FALSE(handle.Get().IsDead()); +} + +} // namespace testing +} // namespace impeller diff --git a/impeller/renderer/backend/metal/compute_pass_mtl.h b/impeller/renderer/backend/metal/compute_pass_mtl.h index 64ff69a70db7b..e44975eee1239 100644 --- a/impeller/renderer/backend/metal/compute_pass_mtl.h +++ b/impeller/renderer/backend/metal/compute_pass_mtl.h @@ -51,14 +51,14 @@ class ComputePassMTL final : public ComputePass { bool BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) override; // |ComputePass| bool BindResource(ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) override; diff --git a/impeller/renderer/backend/metal/compute_pass_mtl.mm b/impeller/renderer/backend/metal/compute_pass_mtl.mm index ee667fccaacb6..ccd51e67c91b7 100644 --- a/impeller/renderer/backend/metal/compute_pass_mtl.mm +++ b/impeller/renderer/backend/metal/compute_pass_mtl.mm @@ -82,7 +82,7 @@ bool ComputePassMTL::BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) { if (!view.GetBuffer()) { return false; @@ -109,7 +109,7 @@ ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { if (!sampler || !texture->IsValid()) { diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index 15bb2fd46e015..a0af10d442a73 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -118,6 +118,9 @@ class ContextMTL final : public Context, // |Context| const std::shared_ptr& GetCapabilities() const override; + // |Context| + RuntimeStageBackend GetRuntimeStageBackend() const override; + void SetCapabilities(const std::shared_ptr& capabilities); // |Context| diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 0a66c82146a31..a4083bfa63eec 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -13,6 +13,7 @@ #include "flutter/fml/paths.h" #include "flutter/fml/synchronization/sync_switch.h" #include "impeller/core/formats.h" +#include "impeller/core/runtime_types.h" #include "impeller/core/sampler_descriptor.h" #include "impeller/renderer/backend/metal/gpu_tracer_mtl.h" #include "impeller/renderer/backend/metal/sampler_library_mtl.h" @@ -430,6 +431,11 @@ new ContextMTL(device, command_queue, return command_queue_ip_; } +// |Context| +RuntimeStageBackend ContextMTL::GetRuntimeStageBackend() const { + return RuntimeStageBackend::kMetal; +} + #ifdef IMPELLER_DEBUG const std::shared_ptr ContextMTL::GetCaptureManager() const { diff --git a/impeller/renderer/backend/metal/render_pass_mtl.h b/impeller/renderer/backend/metal/render_pass_mtl.h index ddef8a7b83c18..ee244ce1e92b6 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.h +++ b/impeller/renderer/backend/metal/render_pass_mtl.h @@ -48,9 +48,6 @@ class RenderPassMTL final : public RenderPass { const RenderTarget& target, id buffer); - // |RenderPass| - void ReserveCommands(size_t command_count) override {} - // |RenderPass| bool IsValid() const override; @@ -99,24 +96,33 @@ class RenderPassMTL final : public RenderPass { bool BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) override; - - // |RenderPass| - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, + const ShaderMetadata* metadata, BufferView view) override; // |RenderPass| bool BindResource(ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) override; + // |RenderPass| + bool BindDynamicResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + std::unique_ptr metadata, + BufferView view) override; + + // |RenderPass| + bool BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) override; + RenderPassMTL(const RenderPassMTL&) = delete; RenderPassMTL& operator=(const RenderPassMTL&) = delete; diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 80cf59bb5f1f7..203e97e36ec90 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -104,15 +104,15 @@ static bool ConfigureStencilAttachment( const RenderTarget& desc) { auto result = [MTLRenderPassDescriptor renderPassDescriptor]; - const auto& colors = desc.GetColorAttachments(); - - for (const auto& color : colors) { - if (!ConfigureColorAttachment(color.second, - result.colorAttachments[color.first])) { - VALIDATION_LOG << "Could not configure color attachment at index " - << color.first; - return nil; - } + bool configured_attachment = desc.IterateAllColorAttachments( + [&result](size_t index, const ColorAttachment& attachment) -> bool { + return ConfigureColorAttachment(attachment, + result.colorAttachments[index]); + }); + + if (!configured_attachment) { + VALIDATION_LOG << "Could not configure color attachments"; + return nil; } const auto& depth = desc.GetDepthAttachment(); @@ -385,17 +385,17 @@ static bool Bind(PassBindingsCacheMTL& pass, bool RenderPassMTL::BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) { return Bind(pass_bindings_, stage, slot.ext_res_0, view); } // |RenderPass| -bool RenderPassMTL::BindResource( +bool RenderPassMTL::BindDynamicResource( ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, + std::unique_ptr metadata, BufferView view) { return Bind(pass_bindings_, stage, slot.ext_res_0, view); } @@ -405,7 +405,20 @@ static bool Bind(PassBindingsCacheMTL& pass, ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) { + if (!texture) { + return false; + } + return Bind(pass_bindings_, stage, slot.texture_index, sampler, *texture); +} + +bool RenderPassMTL::BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { if (!texture) { diff --git a/impeller/renderer/backend/metal/sampler_library_mtl.mm b/impeller/renderer/backend/metal/sampler_library_mtl.mm index 0f24029b42ea1..72538338075c3 100644 --- a/impeller/renderer/backend/metal/sampler_library_mtl.mm +++ b/impeller/renderer/backend/metal/sampler_library_mtl.mm @@ -34,9 +34,11 @@ if (@available(iOS 14.0, macos 10.12, *)) { desc.borderColor = MTLSamplerBorderColorTransparentBlack; } +#ifdef IMPELLER_DEBUG if (!descriptor.label.empty()) { - desc.label = @(descriptor.label.c_str()); + desc.label = @(descriptor.label.data()); } +#endif // IMPELLER_DEBUG auto mtl_sampler = [device_ newSamplerStateWithDescriptor:desc]; if (!mtl_sampler) { diff --git a/impeller/renderer/backend/vulkan/compute_pass_vk.cc b/impeller/renderer/backend/vulkan/compute_pass_vk.cc index 402d4bd24a8d2..f4b61cdba643f 100644 --- a/impeller/renderer/backend/vulkan/compute_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/compute_pass_vk.cc @@ -134,7 +134,7 @@ fml::Status ComputePassVK::Compute(const ISize& grid_size) { bool ComputePassVK::BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) { return BindResource(slot.binding, type, view); } @@ -144,7 +144,7 @@ bool ComputePassVK::BindResource( ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { if (bound_image_offset_ >= kMaxBindings) { diff --git a/impeller/renderer/backend/vulkan/compute_pass_vk.h b/impeller/renderer/backend/vulkan/compute_pass_vk.h index b281775259be1..78aac09c6da45 100644 --- a/impeller/renderer/backend/vulkan/compute_pass_vk.h +++ b/impeller/renderer/backend/vulkan/compute_pass_vk.h @@ -71,14 +71,14 @@ class ComputePassVK final : public ComputePass { bool BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) override; // |ResourceBinder| bool BindResource(ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) override; diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index d793b3e9c61fd..c72f944f48fb6 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -7,6 +7,8 @@ #include #include "fml/concurrent_message_loop.h" +#include "impeller/core/formats.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/vulkan/command_queue_vk.h" #include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h" #include "impeller/renderer/backend/vulkan/render_pass_builder_vk.h" @@ -666,15 +668,18 @@ void ContextVK::InitializeCommonlyUsedShadersIfNeeded() const { rt_allocator.CreateOffscreenMSAA(*this, {1, 1}, 1); RenderPassBuilderVK builder; - for (const auto& [bind_point, color] : render_target.GetColorAttachments()) { - builder.SetColorAttachment( - bind_point, // - color.texture->GetTextureDescriptor().format, // - color.texture->GetTextureDescriptor().sample_count, // - color.load_action, // - color.store_action // - ); - } + + render_target.IterateAllColorAttachments( + [&builder](size_t index, const ColorAttachment& attachment) -> bool { + builder.SetColorAttachment( + index, // + attachment.texture->GetTextureDescriptor().format, // + attachment.texture->GetTextureDescriptor().sample_count, // + attachment.load_action, // + attachment.store_action // + ); + return true; + }); if (auto depth = render_target.GetDepthAttachment(); depth.has_value()) { builder.SetDepthStencilAttachment( @@ -717,4 +722,8 @@ bool ContextVK::GetShouldDisableSurfaceControlSwapchain() const { return should_disable_surface_control_; } +RuntimeStageBackend ContextVK::GetRuntimeStageBackend() const { + return RuntimeStageBackend::kVulkan; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 40bddc494d44e..08ed6569b0097 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -13,6 +13,7 @@ #include "impeller/base/backend_cast.h" #include "impeller/base/strings.h" #include "impeller/core/formats.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/vulkan/command_pool_vk.h" #include "impeller/renderer/backend/vulkan/device_holder_vk.h" #include "impeller/renderer/backend/vulkan/driver_info_vk.h" @@ -229,6 +230,8 @@ class ContextVK final : public Context, // | Context | bool FlushCommandBuffers() override; + RuntimeStageBackend GetRuntimeStageBackend() const override; + std::shared_ptr GetIdleWaiter() const override { return idle_waiter_vk_; } diff --git a/impeller/renderer/backend/vulkan/driver_info_vk.cc b/impeller/renderer/backend/vulkan/driver_info_vk.cc index ec23a22147d18..a53c456560484 100644 --- a/impeller/renderer/backend/vulkan/driver_info_vk.cc +++ b/impeller/renderer/backend/vulkan/driver_info_vk.cc @@ -336,22 +336,18 @@ bool DriverInfoVK::IsEmulator() const { bool DriverInfoVK::IsKnownBadDriver() const { if (adreno_gpu_.has_value()) { - auto adreno = adreno_gpu_.value(); - switch (adreno) { - // See: - // https://github.com/flutter/flutter/issues/154103 - // - // Reports "VK_INCOMPLETE" when compiling certain entity shader with - // vkCreateGraphicsPipelines, which is not a valid return status. - // See https://github.com/flutter/flutter/issues/155185 . - case AdrenoGPU::kAdreno630: - // See: - // https://github.com/flutter/flutter/issues/155185 - // Unknown crashes but device is not easily acquirable. - case AdrenoGPU::kAdreno506: - return true; - default: - return false; + AdrenoGPU adreno = adreno_gpu_.value(); + // See: + // https://github.com/flutter/flutter/issues/154103 + // + // Reports "VK_INCOMPLETE" when compiling certain entity shader with + // vkCreateGraphicsPipelines, which is not a valid return status. + // See https://github.com/flutter/flutter/issues/155185 . + // + // https://github.com/flutter/flutter/issues/155185 + // Unknown crashes but device is not easily acquirable. + if (adreno <= AdrenoGPU::kAdreno630) { + return true; } } // Disable Maleoon series GPUs, see: diff --git a/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc b/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc index 376a23c77f1e1..c1b40ed98e75c 100644 --- a/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc +++ b/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc @@ -106,6 +106,18 @@ TEST(DriverInfoVKTest, DriverParsingAdreno) { TEST(DriverInfoVKTest, DisabledDevices) { EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 630")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 620")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 610")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 530")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 512")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 509")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 508")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 506")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 505")); + EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 504")); + + EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 640")); + EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 650")); } TEST(DriverInfoVKTest, EnabledDevicesMali) { @@ -122,14 +134,6 @@ TEST(DriverInfoVKTest, EnabledDevicesAdreno) { EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 720")); EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 710")); EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 702")); - EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 530")); - EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 512")); - EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 509")); - EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 508")); - EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 505")); - EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 504")); - - EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 506")); } } // namespace impeller::testing diff --git a/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc b/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc index 77f5a3a1e9b14..32f62dddf1907 100644 --- a/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc @@ -48,14 +48,27 @@ RenderPassBuilderVK& RenderPassBuilderVK::SetColorAttachment( desc.initialLayout = vk::ImageLayout::eUndefined; } desc.finalLayout = vk::ImageLayout::eGeneral; - colors_[index] = desc; - if (StoreActionPerformsResolve(store_action)) { - desc.storeOp = ToVKAttachmentStoreOp(store_action, true); - desc.samples = vk::SampleCountFlagBits::e1; - resolves_[index] = desc; + const bool performs_resolves = StoreActionPerformsResolve(store_action); + if (index == 0u) { + color0_ = desc; + + if (performs_resolves) { + desc.storeOp = ToVKAttachmentStoreOp(store_action, true); + desc.samples = vk::SampleCountFlagBits::e1; + color0_resolve_ = desc; + } else { + color0_resolve_ = std::nullopt; + } } else { - resolves_.erase(index); + colors_[index] = desc; + if (performs_resolves) { + desc.storeOp = ToVKAttachmentStoreOp(store_action, true); + desc.samples = vk::SampleCountFlagBits::e1; + resolves_[index] = desc; + } else { + resolves_.erase(index); + } } return *this; } @@ -100,8 +113,11 @@ vk::UniqueRenderPass RenderPassBuilderVK::Build( const vk::Device& device) const { // This must be less than `VkPhysicalDeviceLimits::maxColorAttachments` but we // are not checking. - const auto color_attachments_count = + auto color_attachments_count = colors_.empty() ? 0u : colors_.rbegin()->first + 1u; + if (color0_.has_value()) { + color_attachments_count++; + } std::vector attachments; @@ -111,6 +127,22 @@ vk::UniqueRenderPass RenderPassBuilderVK::Build( kUnusedAttachmentReference); vk::AttachmentReference depth_stencil_ref = kUnusedAttachmentReference; + if (color0_.has_value()) { + vk::AttachmentReference color_ref; + color_ref.attachment = attachments.size(); + color_ref.layout = vk::ImageLayout::eGeneral; + color_refs[0] = color_ref; + attachments.push_back(color0_.value()); + + if (color0_resolve_.has_value()) { + vk::AttachmentReference resolve_ref; + resolve_ref.attachment = attachments.size(); + resolve_ref.layout = vk::ImageLayout::eGeneral; + resolve_refs[0] = resolve_ref; + attachments.push_back(color0_resolve_.value()); + } + } + for (const auto& color : colors_) { vk::AttachmentReference color_ref; color_ref.attachment = attachments.size(); @@ -207,4 +239,16 @@ RenderPassBuilderVK::GetDepthStencil() const { return depth_stencil_; } +// Visible for testing. +std::optional RenderPassBuilderVK::GetColor0() + const { + return color0_; +} + +// Visible for testing. +std::optional RenderPassBuilderVK::GetColor0Resolve() + const { + return color0_resolve_; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/render_pass_builder_vk.h b/impeller/renderer/backend/vulkan/render_pass_builder_vk.h index c3ed390e961b9..4e9632d9a6d13 100644 --- a/impeller/renderer/backend/vulkan/render_pass_builder_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_builder_vk.h @@ -8,6 +8,7 @@ #include #include +#include "flutter/fml/macros.h" #include "impeller/core/formats.h" #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" @@ -54,10 +55,20 @@ class RenderPassBuilderVK { // Visible for testing. const std::optional& GetDepthStencil() const; + // Visible for testing. + std::optional GetColor0() const; + + // Visible for testing. + std::optional GetColor0Resolve() const; + private: + std::optional color0_; + std::optional color0_resolve_; + std::optional depth_stencil_; + + // Color attachment 0 is stored in the field above and not in these maps. std::map colors_; std::map resolves_; - std::optional depth_stencil_; }; //------------------------------------------------------------------------------ diff --git a/impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc b/impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc index 658ae2f54ac88..2aa44c42de0db 100644 --- a/impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc +++ b/impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc @@ -40,9 +40,12 @@ TEST(RenderPassBuilder, RenderPassWithLoadOpUsesCurrentLayout) { EXPECT_TRUE(!!render_pass); - auto maybe_color = builder.GetColorAttachments().find(0u); - ASSERT_NE(maybe_color, builder.GetColorAttachments().end()); - auto color = maybe_color->second; + std::optional maybe_color = builder.GetColor0(); + ASSERT_TRUE(maybe_color.has_value()); + if (!maybe_color.has_value()) { + return; + } + vk::AttachmentDescription color = maybe_color.value(); EXPECT_EQ(color.initialLayout, vk::ImageLayout::eColorAttachmentOptimal); EXPECT_EQ(color.finalLayout, vk::ImageLayout::eGeneral); @@ -66,21 +69,25 @@ TEST(RenderPassBuilder, CreatesRenderPassWithCombinedDepthStencil) { EXPECT_TRUE(!!render_pass); - auto maybe_color = builder.GetColorAttachments().find(0u); - ASSERT_NE(maybe_color, builder.GetColorAttachments().end()); - auto color = maybe_color->second; + std::optional maybe_color = builder.GetColor0(); + ASSERT_TRUE(maybe_color.has_value()); + if (!maybe_color.has_value()) { + return; + } + vk::AttachmentDescription color = maybe_color.value(); EXPECT_EQ(color.initialLayout, vk::ImageLayout::eUndefined); EXPECT_EQ(color.finalLayout, vk::ImageLayout::eGeneral); EXPECT_EQ(color.loadOp, vk::AttachmentLoadOp::eClear); EXPECT_EQ(color.storeOp, vk::AttachmentStoreOp::eStore); - auto maybe_depth_stencil = builder.GetDepthStencil(); + std::optional maybe_depth_stencil = + builder.GetDepthStencil(); ASSERT_TRUE(maybe_depth_stencil.has_value()); if (!maybe_depth_stencil.has_value()) { return; } - auto depth_stencil = maybe_depth_stencil.value(); + vk::AttachmentDescription depth_stencil = maybe_depth_stencil.value(); EXPECT_EQ(depth_stencil.initialLayout, vk::ImageLayout::eUndefined); EXPECT_EQ(depth_stencil.finalLayout, @@ -106,12 +113,13 @@ TEST(RenderPassBuilder, CreatesRenderPassWithOnlyStencil) { EXPECT_TRUE(!!render_pass); - auto maybe_depth_stencil = builder.GetDepthStencil(); + std::optional maybe_depth_stencil = + builder.GetDepthStencil(); ASSERT_TRUE(maybe_depth_stencil.has_value()); if (!maybe_depth_stencil.has_value()) { return; } - auto depth_stencil = maybe_depth_stencil.value(); + vk::AttachmentDescription depth_stencil = maybe_depth_stencil.value(); EXPECT_EQ(depth_stencil.initialLayout, vk::ImageLayout::eUndefined); EXPECT_EQ(depth_stencil.finalLayout, @@ -135,9 +143,12 @@ TEST(RenderPassBuilder, CreatesMSAAResolveWithCorrectStore) { EXPECT_TRUE(!!render_pass); - auto maybe_color = builder.GetColorAttachments().find(0u); - ASSERT_NE(maybe_color, builder.GetColorAttachments().end()); - auto color = maybe_color->second; + auto maybe_color = builder.GetColor0(); + ASSERT_TRUE(maybe_color.has_value()); + if (!maybe_color.has_value()) { + return; + } + vk::AttachmentDescription color = maybe_color.value(); // MSAA Texture. EXPECT_EQ(color.initialLayout, vk::ImageLayout::eUndefined); @@ -145,9 +156,12 @@ TEST(RenderPassBuilder, CreatesMSAAResolveWithCorrectStore) { EXPECT_EQ(color.loadOp, vk::AttachmentLoadOp::eClear); EXPECT_EQ(color.storeOp, vk::AttachmentStoreOp::eDontCare); - auto maybe_resolve = builder.GetResolves().find(0u); - ASSERT_NE(maybe_resolve, builder.GetResolves().end()); - auto resolve = maybe_resolve->second; + auto maybe_resolve = builder.GetColor0Resolve(); + ASSERT_TRUE(maybe_resolve.has_value()); + if (!maybe_resolve.has_value()) { + return; + } + vk::AttachmentDescription resolve = maybe_resolve.value(); // MSAA Resolve Texture. EXPECT_EQ(resolve.initialLayout, vk::ImageLayout::eUndefined); diff --git a/impeller/renderer/backend/vulkan/render_pass_cache_unittests.cc b/impeller/renderer/backend/vulkan/render_pass_cache_unittests.cc index 055c91a3ccb10..f4b470ebe2a3f 100644 --- a/impeller/renderer/backend/vulkan/render_pass_cache_unittests.cc +++ b/impeller/renderer/backend/vulkan/render_pass_cache_unittests.cc @@ -23,8 +23,7 @@ TEST_P(RendererTest, CachesRenderPassAndFramebuffer) { auto render_target = allocator->CreateOffscreenMSAA(*GetContext(), {100, 100}, 1); - auto resolve_texture = - render_target.GetColorAttachments().find(0u)->second.resolve_texture; + auto resolve_texture = render_target.GetColorAttachment(0).resolve_texture; auto& texture_vk = TextureVK::Cast(*resolve_texture); EXPECT_EQ(texture_vk.GetCachedFramebuffer(), nullptr); diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index 3808d84fd34c2..f8a169adfb670 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -56,12 +56,14 @@ static std::vector GetVKClearValues( const RenderTarget& target) { std::vector clears; - for (const auto& [_, color] : target.GetColorAttachments()) { - clears.emplace_back(VKClearValueFromColor(color.clear_color)); - if (color.resolve_texture) { - clears.emplace_back(VKClearValueFromColor(color.clear_color)); - } - } + target.IterateAllColorAttachments( + [&clears](size_t index, const ColorAttachment& attachment) -> bool { + clears.emplace_back(VKClearValueFromColor(attachment.clear_color)); + if (attachment.resolve_texture) { + clears.emplace_back(VKClearValueFromColor(attachment.clear_color)); + } + return true; + }); const auto& depth = target.GetDepthAttachment(); const auto& stencil = target.GetStencilAttachment(); @@ -83,22 +85,24 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( const std::shared_ptr& command_buffer) const { RenderPassBuilderVK builder; - for (const auto& [bind_point, color] : render_target_.GetColorAttachments()) { - builder.SetColorAttachment( - bind_point, // - color.texture->GetTextureDescriptor().format, // - color.texture->GetTextureDescriptor().sample_count, // - color.load_action, // - color.store_action, // - TextureVK::Cast(*color.texture).GetLayout() // - ); - TextureVK::Cast(*color.texture) - .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral); - if (color.resolve_texture) { - TextureVK::Cast(*color.resolve_texture) - .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral); - } - } + render_target_.IterateAllColorAttachments( + [&](size_t bind_point, const ColorAttachment& attachment) -> bool { + builder.SetColorAttachment( + bind_point, // + attachment.texture->GetTextureDescriptor().format, // + attachment.texture->GetTextureDescriptor().sample_count, // + attachment.load_action, // + attachment.store_action, // + TextureVK::Cast(*attachment.texture).GetLayout() // + ); + TextureVK::Cast(*attachment.texture) + .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral); + if (attachment.resolve_texture) { + TextureVK::Cast(*attachment.resolve_texture) + .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral); + } + return true; + }); if (auto depth = render_target_.GetDepthAttachment(); depth.has_value()) { builder.SetDepthStencilAttachment( @@ -137,10 +141,9 @@ RenderPassVK::RenderPassVK(const std::shared_ptr& context, const RenderTarget& target, std::shared_ptr command_buffer) : RenderPass(context, target), command_buffer_(std::move(command_buffer)) { - color_image_vk_ = - render_target_.GetColorAttachments().find(0u)->second.texture; - resolve_image_vk_ = - render_target_.GetColorAttachments().find(0u)->second.resolve_texture; + const ColorAttachment& color0 = render_target_.GetColorAttachment(0); + color_image_vk_ = color0.texture; + resolve_image_vk_ = color0.resolve_texture; const auto& vk_context = ContextVK::Cast(*context); command_buffer_vk_ = command_buffer_->GetCommandBuffer(); @@ -254,16 +257,19 @@ SharedHandleVK RenderPassVK::CreateVKFramebuffer( // This bit must be consistent to ensure compatibility with the pass created // earlier. Follow this order: Color attachments, then depth-stencil, then // stencil. - for (const auto& [_, color] : render_target_.GetColorAttachments()) { - // The bind point doesn't matter here since that information is present in - // the render pass. - attachments.emplace_back( - TextureVK::Cast(*color.texture).GetRenderTargetView()); - if (color.resolve_texture) { - attachments.emplace_back( - TextureVK::Cast(*color.resolve_texture).GetRenderTargetView()); - } - } + render_target_.IterateAllColorAttachments( + [&attachments](size_t index, const ColorAttachment& attachment) -> bool { + // The bind point doesn't matter here since that information is present + // in the render pass. + attachments.emplace_back( + TextureVK::Cast(*attachment.texture).GetRenderTargetView()); + if (attachment.resolve_texture) { + attachments.emplace_back(TextureVK::Cast(*attachment.resolve_texture) + .GetRenderTargetView()); + } + return true; + }); + if (auto depth = render_target_.GetDepthAttachment(); depth.has_value()) { attachments.emplace_back( TextureVK::Cast(*depth->texture).GetRenderTargetView()); @@ -544,17 +550,16 @@ fml::Status RenderPassVK::Draw() { bool RenderPassVK::BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) { return BindResource(slot.binding, type, view); } -bool RenderPassVK::BindResource( - ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view) { +bool RenderPassVK::BindDynamicResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + std::unique_ptr metadata, + BufferView view) { return BindResource(slot.binding, type, view); } @@ -593,10 +598,20 @@ bool RenderPassVK::BindResource(size_t binding, return true; } +bool RenderPassVK::BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) { + return BindResource(stage, type, slot, nullptr, texture, sampler); +} + bool RenderPassVK::BindResource(ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { if (bound_buffer_offset_ >= kMaxBindings) { diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index 61ca7533b0ea5..d442e08882cd2 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -92,31 +92,37 @@ class RenderPassVK final : public RenderPass { // |RenderPass| fml::Status Draw() override; - // |RenderPass| - void ReserveCommands(size_t command_count) override {} - // |ResourceBinder| bool BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) override; - - // |RenderPass| - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, + const ShaderMetadata* metadata, BufferView view) override; // |ResourceBinder| bool BindResource(ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) override; + // |RenderPass| + bool BindDynamicResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + std::unique_ptr metadata, + BufferView view) override; + + // |RenderPass| + bool BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) override; + bool BindResource(size_t binding, DescriptorType type, BufferView view); // |RenderPass| diff --git a/impeller/renderer/backend/vulkan/sampler_vk.cc b/impeller/renderer/backend/vulkan/sampler_vk.cc index 836f9bdd24f7d..8a1eaccf72ae3 100644 --- a/impeller/renderer/backend/vulkan/sampler_vk.cc +++ b/impeller/renderer/backend/vulkan/sampler_vk.cc @@ -92,7 +92,7 @@ static vk::UniqueSampler CreateSampler( } if (!desc.label.empty()) { - ContextVK::SetDebugName(device, sampler.value.get(), desc.label.c_str()); + ContextVK::SetDebugName(device, sampler.value.get(), desc.label.data()); } return std::move(sampler.value); diff --git a/impeller/renderer/backend/vulkan/surface_context_vk.cc b/impeller/renderer/backend/vulkan/surface_context_vk.cc index faaf748df966b..07837626663f2 100644 --- a/impeller/renderer/backend/vulkan/surface_context_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_context_vk.cc @@ -5,6 +5,7 @@ #include "impeller/renderer/backend/vulkan/surface_context_vk.h" #include "flutter/fml/trace_event.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/vulkan/command_pool_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h" @@ -128,4 +129,8 @@ bool SurfaceContextVK::FlushCommandBuffers() { return parent_->FlushCommandBuffers(); } +RuntimeStageBackend SurfaceContextVK::GetRuntimeStageBackend() const { + return parent_->GetRuntimeStageBackend(); +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/surface_context_vk.h b/impeller/renderer/backend/vulkan/surface_context_vk.h index f439ff927af6e..488dc19f900cc 100644 --- a/impeller/renderer/backend/vulkan/surface_context_vk.h +++ b/impeller/renderer/backend/vulkan/surface_context_vk.h @@ -8,6 +8,7 @@ #include #include "impeller/base/backend_cast.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/command_queue.h" #include "impeller/renderer/context.h" @@ -66,8 +67,12 @@ class SurfaceContextVK : public Context, // |Context| std::shared_ptr GetCommandQueue() const override; + // |Context| std::shared_ptr GetIdleWaiter() const override; + // |Context| + RuntimeStageBackend GetRuntimeStageBackend() const override; + // |Context| void Shutdown() override; diff --git a/impeller/renderer/backend/vulkan/test/swapchain_unittests.cc b/impeller/renderer/backend/vulkan/test/swapchain_unittests.cc index 7589f849a15e4..4347df46aa561 100644 --- a/impeller/renderer/backend/vulkan/test/swapchain_unittests.cc +++ b/impeller/renderer/backend/vulkan/test/swapchain_unittests.cc @@ -86,8 +86,7 @@ TEST(SwapchainTest, CachesRenderPassOnSwapchainImage) { auto& depth = render_target.GetDepthAttachment(); depth_stencil_textures.push_back(depth.has_value() ? depth->texture : nullptr); - msaa_textures.push_back( - render_target.GetColorAttachments().find(0u)->second.texture); + msaa_textures.push_back(render_target.GetColorAttachment(0).texture); } for (auto i = 1; i < 3; i++) { diff --git a/impeller/renderer/command.cc b/impeller/renderer/command.cc index 0ca99cbd31155..a981cac62651d 100644 --- a/impeller/renderer/command.cc +++ b/impeller/renderer/command.cc @@ -4,120 +4,8 @@ #include "impeller/renderer/command.h" -#include - -#include "impeller/base/validation.h" -#include "impeller/core/formats.h" -#include "impeller/renderer/vertex_descriptor.h" - namespace impeller { -bool Command::BindVertices(const VertexBuffer& buffer) { - if (buffer.index_type == IndexType::kUnknown) { - VALIDATION_LOG << "Cannot bind vertex buffer with an unknown index type."; - return false; - } - - vertex_buffers = {buffer.vertex_buffer}; - vertex_buffer_count = 1u; - element_count = buffer.vertex_count; - index_buffer = buffer.index_buffer; - index_type = buffer.index_type; - return true; -} - -bool Command::BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) { - FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex); - if (!view) { - return false; - } - - switch (stage) { - case ShaderStage::kVertex: - vertex_bindings.buffers.emplace_back(BufferAndUniformSlot{ - .slot = slot, .view = BufferResource(metadata, std::move(view))}); - return true; - case ShaderStage::kFragment: - fragment_bindings.buffers.emplace_back(BufferAndUniformSlot{ - .slot = slot, .view = BufferResource(metadata, std::move(view))}); - return true; - case ShaderStage::kCompute: - VALIDATION_LOG << "Use ComputeCommands for compute shader stages."; - case ShaderStage::kUnknown: - return false; - } - - return false; -} - -bool Command::BindResource( - ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view) { - FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex); - if (!view) { - return false; - } - - switch (stage) { - case ShaderStage::kVertex: - vertex_bindings.buffers.emplace_back(BufferAndUniformSlot{ - .slot = slot, .view = BufferResource(*metadata, std::move(view))}); - return true; - case ShaderStage::kFragment: - fragment_bindings.buffers.emplace_back(BufferAndUniformSlot{ - .slot = slot, .view = BufferResource(*metadata, std::move(view))}); - return true; - case ShaderStage::kCompute: - VALIDATION_LOG << "Use ComputeCommands for compute shader stages."; - case ShaderStage::kUnknown: - return false; - } - - return false; -} - -bool Command::BindResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - const ShaderMetadata& metadata, - std::shared_ptr texture, - const std::unique_ptr& sampler) { - if (!sampler) { - return false; - } - if (!texture || !texture->IsValid()) { - return false; - } - - switch (stage) { - case ShaderStage::kVertex: - vertex_bindings.sampled_images.emplace_back(TextureAndSampler{ - .slot = slot, - .texture = TextureResource(metadata, std::move(texture)), - .sampler = &sampler, - }); - return true; - case ShaderStage::kFragment: - fragment_bindings.sampled_images.emplace_back(TextureAndSampler{ - .slot = slot, - .texture = TextureResource(metadata, std::move(texture)), - .sampler = &sampler, - }); - return true; - case ShaderStage::kCompute: - VALIDATION_LOG << "Use ComputeCommands for compute shader stages."; - case ShaderStage::kUnknown: - return false; - } - - return false; -} +// } // namespace impeller diff --git a/impeller/renderer/command.h b/impeller/renderer/command.h index 62553269fd6e3..24b64716663cf 100644 --- a/impeller/renderer/command.h +++ b/impeller/renderer/command.h @@ -12,24 +12,17 @@ #include "impeller/core/buffer_view.h" #include "impeller/core/formats.h" -#include "impeller/core/resource_binder.h" #include "impeller/core/sampler.h" #include "impeller/core/shader_types.h" #include "impeller/core/texture.h" -#include "impeller/core/vertex_buffer.h" #include "impeller/geometry/rect.h" #include "impeller/renderer/pipeline.h" namespace impeller { -#ifdef IMPELLER_DEBUG -#define DEBUG_COMMAND_INFO(obj, arg) obj.label = arg; -#else -#define DEBUG_COMMAND_INFO(obj, arg) -#endif // IMPELLER_DEBUG - template -struct Resource { +class Resource { + public: using ResourceType = T; ResourceType resource; @@ -38,20 +31,24 @@ struct Resource { Resource(const ShaderMetadata* metadata, ResourceType p_resource) : resource(p_resource), metadata_(metadata) {} - Resource(const ShaderMetadata& metadata, ResourceType p_resource) - : resource(p_resource), - dynamic_metadata_(std::make_shared(metadata)) {} - const ShaderMetadata* GetMetadata() const { return dynamic_metadata_ ? dynamic_metadata_.get() : metadata_; } + static Resource MakeDynamic(std::unique_ptr metadata, + ResourceType p_resource) { + return Resource(std::move(metadata), p_resource); + } + private: + Resource(std::unique_ptr metadata, ResourceType p_resource) + : resource(p_resource), dynamic_metadata_(std::move(metadata)) {} + // Static shader metadata (typically generated by ImpellerC). const ShaderMetadata* metadata_ = nullptr; // Dynamically generated shader metadata. - std::shared_ptr dynamic_metadata_ = nullptr; + std::unique_ptr dynamic_metadata_ = nullptr; }; using BufferResource = Resource; @@ -60,21 +57,11 @@ using TextureResource = Resource>; /// @brief combines the texture, sampler and sampler slot information. struct TextureAndSampler { SampledImageSlot slot; + ShaderStage stage; TextureResource texture; const std::unique_ptr* sampler; }; -/// @brief combines the buffer resource and its uniform slot information. -struct BufferAndUniformSlot { - ShaderUniformSlot slot; - BufferResource view; -}; - -struct Bindings { - std::vector sampled_images; - std::vector buffers; -}; - //------------------------------------------------------------------------------ /// @brief An object used to specify work to the GPU along with references /// to resources the GPU will used when doing said work. @@ -89,21 +76,16 @@ struct Bindings { /// referenced in commands views into buffers managed by other /// allocators and resource managers. /// -struct Command : public ResourceBinder { +struct Command { //---------------------------------------------------------------------------- /// The pipeline to use for this command. /// std::shared_ptr> pipeline; - //---------------------------------------------------------------------------- - /// The buffer, texture, and sampler bindings used by the vertex pipeline - /// stage. - /// - Bindings vertex_bindings; - //---------------------------------------------------------------------------- - /// The buffer, texture, and sampler bindings used by the fragment pipeline - /// stage. - /// - Bindings fragment_bindings; + + /// An offset into render pass storage where bound buffers/texture metadata is + /// stored. + Range bound_buffers = Range{0, 0}; + Range bound_textures = Range{0, 0}; #ifdef IMPELLER_DEBUG //---------------------------------------------------------------------------- @@ -147,13 +129,10 @@ struct Command : public ResourceBinder { size_t instance_count = 1u; //---------------------------------------------------------------------------- - /// The vertex buffers used by the vertex shader stage. - std::array vertex_buffers; - - //---------------------------------------------------------------------------- - /// The number of vertex buffers in the vertex_buffers array. Must not exceed - /// kMaxVertexBuffers. - size_t vertex_buffer_count = 0u; + /// An offset and range of vertex buffers bound for this draw call. + /// + /// The vertex buffers are stored on the render pass object. + Range vertex_buffers; //---------------------------------------------------------------------------- /// The index buffer binding used by the vertex shader stage. @@ -169,45 +148,7 @@ struct Command : public ResourceBinder { /// packed in the index buffer. IndexType index_type = IndexType::kUnknown; - //---------------------------------------------------------------------------- - /// @brief Specify the vertex and index buffer to use for this command. - /// - /// @param[in] buffer The vertex and index buffer definition. If possible, - /// this value should be moved and not copied. - /// - /// @return returns if the binding was updated. - /// - bool BindVertices(const VertexBuffer& buffer); - - // |ResourceBinder| - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) override; - - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view); - - // |ResourceBinder| - bool BindResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - const ShaderMetadata& metadata, - std::shared_ptr texture, - const std::unique_ptr& sampler) override; - bool IsValid() const { return pipeline && pipeline->IsValid(); } - - private: - template - bool DoBindResource(ShaderStage stage, - const ShaderUniformSlot& slot, - T metadata, - BufferView view); }; } // namespace impeller diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 62254504b9fa9..71bad511288d2 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -236,6 +236,12 @@ class Context { /// virtual void ResetThreadLocalState() const; + /// @brief Retrieve the runtime stage for this context type. + /// + /// This is used by the engine shell and other subsystems for loading the + /// correct shader types. + virtual RuntimeStageBackend GetRuntimeStageBackend() const = 0; + protected: Context(); diff --git a/impeller/renderer/render_pass.cc b/impeller/renderer/render_pass.cc index 016a7a16f13bf..a7f00ff286a4c 100644 --- a/impeller/renderer/render_pass.cc +++ b/impeller/renderer/render_pass.cc @@ -63,15 +63,6 @@ bool RenderPass::AddCommand(Command&& command) { return false; } - if (command.scissor.has_value()) { - auto target_rect = IRect::MakeSize(render_target_.GetRenderTargetSize()); - if (!target_rect.Contains(command.scissor.value())) { - VALIDATION_LOG << "Cannot apply a scissor that lies outside the bounds " - "of the render target."; - return false; - } - } - if (command.element_count == 0u || command.instance_count == 0u) { // Essentially a no-op. Don't record the command but this is not necessary // an error either. @@ -151,9 +142,13 @@ bool RenderPass::SetVertexBuffer(BufferView vertex_buffers[], return false; } - pending_.vertex_buffer_count = vertex_buffer_count; + if (!vertex_buffers_start_.has_value()) { + vertex_buffers_start_ = vertex_buffers_.size(); + } + + pending_.vertex_buffers.length += vertex_buffer_count; for (size_t i = 0; i < vertex_buffer_count; i++) { - pending_.vertex_buffers[i] = std::move(vertex_buffers[i]); + vertex_buffers_.push_back(vertex_buffers[i]); } return true; } @@ -203,8 +198,14 @@ bool RenderPass::ValidateIndexBuffer(const BufferView& index_buffer, } fml::Status RenderPass::Draw() { + pending_.bound_buffers.offset = bound_buffers_start_.value_or(0u); + pending_.bound_textures.offset = bound_textures_start_.value_or(0u); + pending_.vertex_buffers.offset = vertex_buffers_start_.value_or(0u); auto result = AddCommand(std::move(pending_)); pending_ = Command{}; + bound_textures_start_ = std::nullopt; + bound_buffers_start_ = std::nullopt; + vertex_buffers_start_ = std::nullopt; if (result) { return fml::Status(); } @@ -216,29 +217,95 @@ fml::Status RenderPass::Draw() { bool RenderPass::BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) { - return pending_.BindResource(stage, type, slot, metadata, view); -} - -bool RenderPass::BindResource( - ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view) { - return pending_.BindResource(stage, type, slot, metadata, std::move(view)); + FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex); + if (!view) { + return false; + } + BufferResource resouce = BufferResource(metadata, std::move(view)); + return BindBuffer(stage, slot, std::move(resouce)); } // |ResourceBinder| bool RenderPass::BindResource(ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { - return pending_.BindResource(stage, type, slot, metadata, std::move(texture), - sampler); + if (!sampler) { + return false; + } + if (!texture || !texture->IsValid()) { + return false; + } + TextureResource resource = TextureResource(metadata, std::move(texture)); + return BindTexture(stage, slot, std::move(resource), sampler); +} + +bool RenderPass::BindDynamicResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + std::unique_ptr metadata, + BufferView view) { + FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex); + if (!view) { + return false; + } + BufferResource resouce = + BufferResource::MakeDynamic(std::move(metadata), std::move(view)); + + return BindBuffer(stage, slot, std::move(resouce)); +} + +bool RenderPass::BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) { + if (!sampler) { + return false; + } + if (!texture || !texture->IsValid()) { + return false; + } + TextureResource resource = + TextureResource::MakeDynamic(std::move(metadata), std::move(texture)); + return BindTexture(stage, slot, std::move(resource), sampler); +} + +bool RenderPass::BindBuffer(ShaderStage stage, + const ShaderUniformSlot& slot, + BufferResource resource) { + if (!bound_buffers_start_.has_value()) { + bound_buffers_start_ = bound_buffers_.size(); + } + + pending_.bound_buffers.length++; + bound_buffers_.push_back(std::move(resource)); + return true; +} + +bool RenderPass::BindTexture(ShaderStage stage, + const SampledImageSlot& slot, + TextureResource resource, + const std::unique_ptr& sampler) { + TextureAndSampler data = TextureAndSampler{ + .stage = stage, + .texture = std::move(resource), + .sampler = &sampler, + }; + + if (!bound_textures_start_.has_value()) { + bound_textures_start_ = bound_textures_.size(); + } + + pending_.bound_textures.length++; + bound_textures_.push_back(std::move(data)); + return true; } } // namespace impeller diff --git a/impeller/renderer/render_pass.h b/impeller/renderer/render_pass.h index 0ada25e744513..20d85111d90fc 100644 --- a/impeller/renderer/render_pass.h +++ b/impeller/renderer/render_pass.h @@ -18,9 +18,6 @@ namespace impeller { -class HostBuffer; -class Allocator; - //------------------------------------------------------------------------------ /// @brief Render passes encode render commands directed as one specific /// render target into an underlying command buffer. @@ -46,13 +43,6 @@ class RenderPass : public ResourceBinder { void SetLabel(std::string_view label); - /// @brief Reserve [command_count] commands in the HAL command buffer. - /// - /// Note: this is not the native command buffer. - virtual void ReserveCommands(size_t command_count) { - commands_.reserve(command_count); - } - //---------------------------------------------------------------------------- /// The pipeline to use for this command. virtual void SetPipeline( @@ -181,24 +171,33 @@ class RenderPass : public ResourceBinder { virtual bool BindResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, + const ShaderMetadata* metadata, BufferView view) override; + // |ResourceBinder| virtual bool BindResource( ShaderStage stage, DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view); + const SampledImageSlot& slot, + const ShaderMetadata* metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) override; - // |ResourceBinder| - virtual bool BindResource( + /// @brief Bind with dynamically generated shader metadata. + virtual bool BindDynamicResource( ShaderStage stage, DescriptorType type, const SampledImageSlot& slot, - const ShaderMetadata& metadata, + std::unique_ptr metadata, std::shared_ptr texture, - const std::unique_ptr& sampler) override; + const std::unique_ptr& sampler); + + /// @brief Bind with dynamically generated shader metadata. + virtual bool BindDynamicResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + std::unique_ptr metadata, + BufferView view); //---------------------------------------------------------------------------- /// @brief Encode the recorded commands to the underlying command buffer. @@ -245,6 +244,9 @@ class RenderPass : public ResourceBinder { const ISize render_target_size_; const RenderTarget render_target_; std::vector commands_; + std::vector vertex_buffers_; + std::vector bound_buffers_; + std::vector bound_textures_; const Matrix orthographic_; //---------------------------------------------------------------------------- @@ -276,7 +278,19 @@ class RenderPass : public ResourceBinder { RenderPass& operator=(const RenderPass&) = delete; + bool BindBuffer(ShaderStage stage, + const ShaderUniformSlot& slot, + BufferResource resource); + + bool BindTexture(ShaderStage stage, + const SampledImageSlot& slot, + TextureResource resource, + const std::unique_ptr& sampler); + Command pending_; + std::optional bound_buffers_start_ = std::nullopt; + std::optional bound_textures_start_ = std::nullopt; + std::optional vertex_buffers_start_ = std::nullopt; }; } // namespace impeller diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index dd70f9f202a9d..b3621e706b659 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -28,6 +28,7 @@ bool RenderTarget::IsValid() const { return false; } +#ifndef NDEBUG // Validate that all attachments are of the same size. { std::optional size; @@ -87,12 +88,34 @@ bool RenderTarget::IsValid() const { return false; } } +#endif // NDEBUG return true; } +bool RenderTarget::IterateAllColorAttachments( + const std::function& + iterator) const { + if (color0_.has_value()) { + if (!iterator(0, color0_.value())) { + return false; + } + } + for (const auto& [index, attachment] : colors_) { + if (!iterator(index, attachment)) { + return false; + } + } + return true; +} + void RenderTarget::IterateAllAttachments( const std::function& iterator) const { + if (color0_.has_value()) { + if (!iterator(color0_.value())) { + return; + } + } for (const auto& color : colors_) { if (!iterator(color.second)) { return; @@ -113,13 +136,16 @@ void RenderTarget::IterateAllAttachments( } SampleCount RenderTarget::GetSampleCount() const { - if (auto found = colors_.find(0u); found != colors_.end()) { - return found->second.texture->GetTextureDescriptor().sample_count; + if (color0_.has_value()) { + return color0_.value().texture->GetTextureDescriptor().sample_count; } return SampleCount::kCount1; } bool RenderTarget::HasColorAttachment(size_t index) const { + if (index == 0u) { + return color0_.has_value(); + } if (auto found = colors_.find(index); found != colors_.end()) { return true; } @@ -127,6 +153,12 @@ bool RenderTarget::HasColorAttachment(size_t index) const { } std::optional RenderTarget::GetColorAttachmentSize(size_t index) const { + if (index == 0u) { + if (color0_.has_value()) { + return color0_.value().texture->GetSize(); + } + return std::nullopt; + } auto found = colors_.find(index); if (found == colors_.end()) { @@ -142,12 +174,10 @@ ISize RenderTarget::GetRenderTargetSize() const { } std::shared_ptr RenderTarget::GetRenderTargetTexture() const { - auto found = colors_.find(0u); - if (found == colors_.end()) { + if (!color0_.has_value()) { return nullptr; } - return found->second.resolve_texture ? found->second.resolve_texture - : found->second.texture; + return color0_->resolve_texture ? color0_->resolve_texture : color0_->texture; } PixelFormat RenderTarget::GetRenderTargetPixelFormat() const { @@ -169,7 +199,12 @@ size_t RenderTarget::GetMaxColorAttacmentBindIndex() const { RenderTarget& RenderTarget::SetColorAttachment( const ColorAttachment& attachment, size_t index) { - if (attachment.IsValid()) { + if (!attachment.IsValid()) { + return *this; + } + if (index == 0u) { + color0_ = attachment; + } else { colors_[index] = attachment; } return *this; @@ -195,9 +230,18 @@ RenderTarget& RenderTarget::SetStencilAttachment( return *this; } -const std::map& RenderTarget::GetColorAttachments() - const { - return colors_; +ColorAttachment RenderTarget::GetColorAttachment(size_t index) const { + if (index == 0) { + if (color0_.has_value()) { + return color0_.value(); + } + return ColorAttachment{}; + } + std::map::const_iterator it = colors_.find(index); + if (it != colors_.end()) { + return it->second; + } + return ColorAttachment{}; } const std::optional& RenderTarget::GetDepthAttachment() const { @@ -219,6 +263,9 @@ size_t RenderTarget::GetTotalAttachmentCount() const { count++; } } + if (color0_.has_value()) { + count++; + } if (depth_.has_value()) { count++; } @@ -231,6 +278,10 @@ size_t RenderTarget::GetTotalAttachmentCount() const { std::string RenderTarget::ToString() const { std::stringstream stream; + if (color0_.has_value()) { + stream << SPrintF("Color[%d]=(%s)", 0, + ColorAttachmentToString(color0_.value()).c_str()); + } for (const auto& [index, color] : colors_) { stream << SPrintF("Color[%zu]=(%s)", index, ColorAttachmentToString(color).c_str()); @@ -248,6 +299,18 @@ std::string RenderTarget::ToString() const { return stream.str(); } +RenderTargetConfig RenderTarget::ToConfig() const { + if (!color0_.has_value()) { + return RenderTargetConfig{}; + } + const auto& color_attachment = color0_.value(); + return RenderTargetConfig{ + .size = color_attachment.texture->GetSize(), + .mip_count = color_attachment.texture->GetMipCount(), + .has_msaa = color_attachment.resolve_texture != nullptr, + .has_depth_stencil = depth_.has_value() && stencil_.has_value()}; +} + RenderTargetAllocator::RenderTargetAllocator( std::shared_ptr allocator) : allocator_(std::move(allocator)) {} diff --git a/impeller/renderer/render_target.h b/impeller/renderer/render_target.h index 77f5bf43f5e38..a7a1e0bd32c9a 100644 --- a/impeller/renderer/render_target.h +++ b/impeller/renderer/render_target.h @@ -102,6 +102,13 @@ class RenderTarget final { RenderTarget& SetColorAttachment(const ColorAttachment& attachment, size_t index); + /// @brief Get the color attachment at [index]. + /// + /// This function does not validate whether or not the attachment was + /// previously defined and will return a default constructed attachment + /// if none is set. + ColorAttachment GetColorAttachment(size_t index) const; + RenderTarget& SetDepthAttachment(std::optional attachment); RenderTarget& SetStencilAttachment( @@ -109,32 +116,32 @@ class RenderTarget final { size_t GetMaxColorAttacmentBindIndex() const; - const std::map& GetColorAttachments() const; - const std::optional& GetDepthAttachment() const; const std::optional& GetStencilAttachment() const; size_t GetTotalAttachmentCount() const; + bool IterateAllColorAttachments( + const std::function& iterator) + const; + void IterateAllAttachments( const std::function& iterator) const; std::string ToString() const; - RenderTargetConfig ToConfig() const { - auto& color_attachment = GetColorAttachments().find(0)->second; - return RenderTargetConfig{ - .size = color_attachment.texture->GetSize(), - .mip_count = color_attachment.texture->GetMipCount(), - .has_msaa = color_attachment.resolve_texture != nullptr, - .has_depth_stencil = depth_.has_value() && stencil_.has_value()}; - } + RenderTargetConfig ToConfig() const; private: - std::map colors_; + std::optional color0_; std::optional depth_; std::optional stencil_; + // Note: color0 is stored in the color0_ field above and not in this map, + // to avoid heap allocations for the commonly created render target formats + // in Flutter. + std::map colors_; }; /// @brief a wrapper around the impeller [Allocator] instance that can be used diff --git a/impeller/renderer/renderer_unittests.cc b/impeller/renderer/renderer_unittests.cc index 633ad6ddba897..0e84ea50cfd17 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -589,10 +589,6 @@ TEST_P(RendererTest, CanBlitTextureToTexture) { } pass->SetLabel("Playground Blit Pass"); - if (render_target.GetColorAttachments().empty()) { - return false; - } - // Blit `bridge` to the top left corner of the texture. pass->AddCopy(bridge, texture); @@ -709,10 +705,6 @@ TEST_P(RendererTest, CanBlitTextureToBuffer) { } pass->SetLabel("Playground Blit Pass"); - if (render_target.GetColorAttachments().empty()) { - return false; - } - // Blit `bridge` to the top left corner of the texture. pass->AddCopy(bridge, device_buffer); pass->EncodeCommands(context->GetResourceAllocator()); diff --git a/impeller/renderer/testing/mocks.h b/impeller/renderer/testing/mocks.h index c020daacfe4d2..d8eca488be5ea 100644 --- a/impeller/renderer/testing/mocks.h +++ b/impeller/renderer/testing/mocks.h @@ -7,6 +7,7 @@ #include "gmock/gmock.h" #include "impeller/core/allocator.h" +#include "impeller/core/runtime_types.h" #include "impeller/core/sampler_descriptor.h" #include "impeller/core/texture.h" #include "impeller/renderer/command_buffer.h" @@ -184,6 +185,11 @@ class MockImpellerContext : public Context { GetCommandQueue, (), (const, override)); + + MOCK_METHOD(RuntimeStageBackend, + GetRuntimeStageBackend, + (), + (const, override)); }; class MockTexture : public Texture { diff --git a/impeller/runtime_stage/runtime_stage.cc b/impeller/runtime_stage/runtime_stage.cc index bf46e805a93eb..634274ac214b4 100644 --- a/impeller/runtime_stage/runtime_stage.cc +++ b/impeller/runtime_stage/runtime_stage.cc @@ -75,6 +75,8 @@ RuntimeStage::Map RuntimeStage::DecodeRuntimeStages( RuntimeStageIfPresent(raw_stages->metal(), payload)}, {RuntimeStageBackend::kOpenGLES, RuntimeStageIfPresent(raw_stages->opengles(), payload)}, + {RuntimeStageBackend::kOpenGLES3, + RuntimeStageIfPresent(raw_stages->opengles3(), payload)}, {RuntimeStageBackend::kVulkan, RuntimeStageIfPresent(raw_stages->vulkan(), payload)}, }; diff --git a/impeller/runtime_stage/runtime_stage_types.fbs b/impeller/runtime_stage/runtime_stage_types.fbs index 39c8af71cfdbc..dd9f7f5a66d71 100644 --- a/impeller/runtime_stage/runtime_stage_types.fbs +++ b/impeller/runtime_stage/runtime_stage_types.fbs @@ -83,5 +83,6 @@ table RuntimeStages { sksl: RuntimeStage; metal: RuntimeStage; opengles: RuntimeStage; + opengles3: RuntimeStage; vulkan: RuntimeStage; } diff --git a/impeller/tessellator/dart/pubspec.yaml b/impeller/tessellator/dart/pubspec.yaml index ef84e428bd7db..618220c2e93e0 100644 --- a/impeller/tessellator/dart/pubspec.yaml +++ b/impeller/tessellator/dart/pubspec.yaml @@ -6,7 +6,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/impeller/toolkit/interop/color_filter.cc b/impeller/toolkit/interop/color_filter.cc index 7e5b2da2b2673..01825aa266137 100644 --- a/impeller/toolkit/interop/color_filter.cc +++ b/impeller/toolkit/interop/color_filter.cc @@ -7,7 +7,7 @@ namespace impeller::interop { ScopedObject ColorFilter::MakeBlend(Color color, BlendMode mode) { - auto filter = flutter::DlBlendColorFilter::Make(ToDisplayListType(color), + auto filter = flutter::DlColorFilter::MakeBlend(ToDisplayListType(color), ToDisplayListType(mode)); if (!filter) { return nullptr; @@ -16,20 +16,20 @@ ScopedObject ColorFilter::MakeBlend(Color color, BlendMode mode) { } ScopedObject ColorFilter::MakeMatrix(const float matrix[20]) { - auto filter = flutter::DlMatrixColorFilter::Make(matrix); + auto filter = flutter::DlColorFilter::MakeMatrix(matrix); if (!filter) { return nullptr; } return Create(std::move(filter)); } -ColorFilter::ColorFilter(std::shared_ptr filter) +ColorFilter::ColorFilter(std::shared_ptr filter) : filter_(std::move(filter)) {} ColorFilter::~ColorFilter() = default; -const std::shared_ptr& ColorFilter::GetColorFilter() - const { +const std::shared_ptr& +ColorFilter::GetColorFilter() const { return filter_; } diff --git a/impeller/toolkit/interop/color_filter.h b/impeller/toolkit/interop/color_filter.h index 70c0c6ec98c19..2f0b066a98b3e 100644 --- a/impeller/toolkit/interop/color_filter.h +++ b/impeller/toolkit/interop/color_filter.h @@ -20,7 +20,7 @@ class ColorFilter final static ScopedObject MakeMatrix(const float matrix[20]); - explicit ColorFilter(std::shared_ptr filter); + explicit ColorFilter(std::shared_ptr filter); ~ColorFilter() override; @@ -28,10 +28,10 @@ class ColorFilter final ColorFilter& operator=(const ColorFilter&) = delete; - const std::shared_ptr& GetColorFilter() const; + const std::shared_ptr& GetColorFilter() const; private: - std::shared_ptr filter_; + std::shared_ptr filter_; }; } // namespace impeller::interop diff --git a/impeller/tools/compiler.gni b/impeller/tools/compiler.gni index 6c2d080865ee1..180600b8ea93d 100644 --- a/impeller/tools/compiler.gni +++ b/impeller/tools/compiler.gni @@ -36,6 +36,7 @@ template("_impellerc") { # --vulkan # --runtime-stage-metal # --runtime-stage-gles +# --runtime-stage-gles3 # --runtime-stage-vulkan # Not required for --shader_bundle mode. # Required: sl_file_extension The file extension to use for output files. diff --git a/impeller/tools/shaders.gni b/impeller/tools/shaders.gni index e0bd24183dc03..140b886552de4 100644 --- a/impeller/tools/shaders.gni +++ b/impeller/tools/shaders.gni @@ -97,6 +97,7 @@ template("impeller_shaders") { analyze = false } gles_shaders = "gles_$target_name" + impeller_shaders_gles(gles_shaders) { name = invoker.name require_framebuffer_fetch = require_framebuffer_fetch @@ -110,6 +111,22 @@ template("impeller_shaders") { } analyze = analyze } + + gles3_shaders = "gles3_$target_name" + + impeller_shaders_gles(gles3_shaders) { + name = invoker.name + require_framebuffer_fetch = require_framebuffer_fetch + gles_language_version = 300 + is_300 = true + analyze = false + if (defined(invoker.gles_exclusions)) { + shaders = invoker.shaders - invoker.gles_exclusions + } else { + shaders = invoker.shaders + } + analyze = analyze + } } if (impeller_enable_vulkan) { @@ -139,7 +156,10 @@ template("impeller_shaders") { } if (enable_opengles) { - public_deps += [ ":$gles_shaders" ] + public_deps += [ + ":$gles3_shaders", + ":$gles_shaders", + ] } if (impeller_enable_vulkan) { diff --git a/impeller/tools/shaders_gles.gni b/impeller/tools/shaders_gles.gni index 903be3fedb5bd..9839227daa004 100644 --- a/impeller/tools/shaders_gles.gni +++ b/impeller/tools/shaders_gles.gni @@ -19,6 +19,8 @@ template("impeller_shaders_gles") { require_framebuffer_fetch = invoker.require_framebuffer_fetch } + is_300 = defined(invoker.is_300) && invoker.is_300 + shaders_base_name = string_join("", [ invoker.name, @@ -35,11 +37,18 @@ template("impeller_shaders_gles") { # Metal reflectors generate a superset of information. if (impeller_enable_metal || impeller_enable_vulkan) { - intermediates_subdir = "gles" + if (is_300) { + intermediates_subdir = "gles3" + } else { + intermediates_subdir = "gles" + } } shader_target_flags = [ "--opengl-es" ] defines = [ "IMPELLER_TARGET_OPENGLES" ] + if (is_300) { + defines += [ "IMPELLER_TARGET_OPENGLES3" ] + } } gles_shaders = @@ -68,13 +77,24 @@ template("impeller_shaders_gles") { } embed_gles_lib = "embed_$target_name" - embed_blob(embed_gles_lib) { - gles_library_files = get_target_outputs(":$gles_lib") - symbol_name = shaders_base_name - blob = gles_library_files[0] - hdr = "$target_gen_dir/gles/$shaders_base_name.h" - cc = "$target_gen_dir/gles/$shaders_base_name.cc" - deps = [ ":$gles_lib" ] + if (is_300) { + embed_blob(embed_gles_lib) { + gles_library_files = get_target_outputs(":$gles_lib") + symbol_name = shaders_base_name + "3" + blob = gles_library_files[0] + hdr = "$target_gen_dir/gles3/$shaders_base_name.h" + cc = "$target_gen_dir/gles3/$shaders_base_name.cc" + deps = [ ":$gles_lib" ] + } + } else { + embed_blob(embed_gles_lib) { + gles_library_files = get_target_outputs(":$gles_lib") + symbol_name = shaders_base_name + blob = gles_library_files[0] + hdr = "$target_gen_dir/gles/$shaders_base_name.h" + cc = "$target_gen_dir/gles/$shaders_base_name.cc" + deps = [ ":$gles_lib" ] + } } group(target_name) { diff --git a/impeller/typographer/BUILD.gn b/impeller/typographer/BUILD.gn index acdbeb80a8e4d..3470c3d0bead5 100644 --- a/impeller/typographer/BUILD.gn +++ b/impeller/typographer/BUILD.gn @@ -34,6 +34,11 @@ impeller_component("typographer") { "../renderer", ] + if (!is_fuchsia) { + public_deps += + [ "//flutter/third_party/abseil-cpp/absl/container:flat_hash_map" ] + } + deps = [ "//flutter/fml" ] } diff --git a/impeller/typographer/backends/skia/typographer_context_skia.cc b/impeller/typographer/backends/skia/typographer_context_skia.cc index 80b499352b557..de7e5b5c29b95 100644 --- a/impeller/typographer/backends/skia/typographer_context_skia.cc +++ b/impeller/typographer/backends/skia/typographer_context_skia.cc @@ -5,6 +5,7 @@ #include "impeller/typographer/backends/skia/typographer_context_skia.h" #include +#include #include #include #include @@ -413,18 +414,23 @@ TypographerContextSkia::CollectNewGlyphs( const std::vector>& text_frames) { std::vector new_glyphs; std::vector glyph_sizes; + size_t generation_id = atlas->GetAtlasGeneration(); + intptr_t atlas_id = reinterpret_cast(atlas.get()); for (const auto& frame : text_frames) { - // TODO(jonahwilliams): unless we destroy the atlas (which we know about), - // we could probably guarantee that a text frame that is complete does not - // need to be processed unless the scale or properties changed. I'm leaving - // this as a future optimization. + auto [frame_generation_id, frame_atlas_id] = + frame->GetAtlasGenerationAndID(); + if (atlas->IsValid() && frame->IsFrameComplete() && + frame_generation_id == generation_id && frame_atlas_id == atlas_id && + !frame->GetFrameBounds(0).is_placeholder) { + continue; + } frame->ClearFrameBounds(); + frame->SetAtlasGeneration(generation_id, atlas_id); for (const auto& run : frame->GetRuns()) { auto metrics = run.GetFont().GetMetrics(); - auto rounded_scale = - TextFrame::RoundScaledFontSize(frame->GetScale(), metrics.point_size); + auto rounded_scale = TextFrame::RoundScaledFontSize(frame->GetScale()); ScaledFont scaled_font{.font = run.GetFont(), .scale = rounded_scale}; FontGlyphAtlas* font_glyph_atlas = @@ -566,7 +572,8 @@ std::shared_ptr TypographerContextSkia::CreateGlyphAtlas( if (atlas_context->GetAtlasSize().height >= max_texture_height || context.GetBackendType() == Context::BackendType::kOpenGLES) { blit_old_atlas = false; - new_atlas = std::make_shared(type); + new_atlas = std::make_shared( + type, /*initial_generation=*/last_atlas->GetAtlasGeneration() + 1); auto [update_glyphs, update_sizes] = CollectNewGlyphs(new_atlas, text_frames); diff --git a/impeller/typographer/font_glyph_pair.h b/impeller/typographer/font_glyph_pair.h index e530f5b3edcda..d5b8906de8c3f 100644 --- a/impeller/typographer/font_glyph_pair.h +++ b/impeller/typographer/font_glyph_pair.h @@ -20,6 +20,17 @@ struct GlyphProperties { Join stroke_join = Join::kMiter; Scalar stroke_miter = 4.0; bool stroke = false; + + struct Equal { + constexpr bool operator()(const impeller::GlyphProperties& lhs, + const impeller::GlyphProperties& rhs) const { + return lhs.color.ToARGB() == rhs.color.ToARGB() && + lhs.stroke == rhs.stroke && lhs.stroke_cap == rhs.stroke_cap && + lhs.stroke_join == rhs.stroke_join && + lhs.stroke_miter == rhs.stroke_miter && + lhs.stroke_width == rhs.stroke_width; + } + }; }; //------------------------------------------------------------------------------ @@ -30,11 +41,10 @@ struct ScaledFont { Font font; Scalar scale; - struct Hash { - constexpr std::size_t operator()(const impeller::ScaledFont& sf) const { - return fml::HashCombine(sf.font.GetHash(), sf.scale); - } - }; + template + friend H AbslHashValue(H h, const ScaledFont& sf) { + return H::combine(std::move(h), sf.font.GetHash(), sf.scale); + } struct Equal { constexpr bool operator()(const impeller::ScaledFont& lhs, @@ -59,38 +69,36 @@ struct SubpixelGlyph { subpixel_offset(p_subpixel_offset), properties(p_properties) {} - struct Hash { - constexpr std::size_t operator()(const impeller::SubpixelGlyph& sg) const { - if (!sg.properties.has_value()) { - return fml::HashCombine(sg.glyph.index, sg.subpixel_offset.x, - sg.subpixel_offset.y); - } - return fml::HashCombine( - sg.glyph.index, sg.subpixel_offset.x, sg.subpixel_offset.y, - sg.properties->color.ToARGB(), sg.properties->stroke, - sg.properties->stroke_cap, sg.properties->stroke_join, - sg.properties->stroke_miter, sg.properties->stroke_width); + template + friend H AbslHashValue(H h, const SubpixelGlyph& sg) { + if (!sg.properties.has_value()) { + return H::combine(std::move(h), sg.glyph.index, sg.subpixel_offset.x, + sg.subpixel_offset.y); } - }; + return H::combine(std::move(h), sg.glyph.index, sg.subpixel_offset.x, + sg.subpixel_offset.y, sg.properties->color.ToARGB(), + sg.properties->stroke, sg.properties->stroke_cap, + sg.properties->stroke_join, sg.properties->stroke_miter, + sg.properties->stroke_width); + } struct Equal { constexpr bool operator()(const impeller::SubpixelGlyph& lhs, const impeller::SubpixelGlyph& rhs) const { - if (!lhs.properties.has_value() && !rhs.properties.has_value()) { - return lhs.glyph.index == rhs.glyph.index && - lhs.glyph.type == rhs.glyph.type && - lhs.subpixel_offset == rhs.subpixel_offset; + // Check simple non-optionals first. + if (lhs.glyph.index != rhs.glyph.index || + lhs.glyph.type != rhs.glyph.type || + lhs.subpixel_offset != rhs.subpixel_offset || + // Mixmatch properties. + lhs.properties.has_value() != rhs.properties.has_value()) { + return false; + } + if (lhs.properties.has_value()) { + // Both have properties. + return GlyphProperties::Equal{}(lhs.properties.value(), + rhs.properties.value()); } - return lhs.glyph.index == rhs.glyph.index && - lhs.glyph.type == rhs.glyph.type && - lhs.subpixel_offset == rhs.subpixel_offset && - lhs.properties.has_value() && rhs.properties.has_value() && - lhs.properties->color.ToARGB() == rhs.properties->color.ToARGB() && - lhs.properties->stroke == rhs.properties->stroke && - lhs.properties->stroke_cap == rhs.properties->stroke_cap && - lhs.properties->stroke_join == rhs.properties->stroke_join && - lhs.properties->stroke_miter == rhs.properties->stroke_miter && - lhs.properties->stroke_width == rhs.properties->stroke_width; + return true; } }; }; diff --git a/impeller/typographer/glyph_atlas.cc b/impeller/typographer/glyph_atlas.cc index 093593804ea5f..9d75d6271065c 100644 --- a/impeller/typographer/glyph_atlas.cc +++ b/impeller/typographer/glyph_atlas.cc @@ -12,7 +12,8 @@ namespace impeller { GlyphAtlasContext::GlyphAtlasContext(GlyphAtlas::Type type) - : atlas_(std::make_shared(type)), atlas_size_(ISize(0, 0)) {} + : atlas_(std::make_shared(type, /*initial_generation=*/0)), + atlas_size_(ISize(0, 0)) {} GlyphAtlasContext::~GlyphAtlasContext() {} @@ -45,7 +46,8 @@ void GlyphAtlasContext::UpdateRectPacker( rect_packer_ = std::move(rect_packer); } -GlyphAtlas::GlyphAtlas(Type type) : type_(type) {} +GlyphAtlas::GlyphAtlas(Type type, size_t initial_generation) + : type_(type), generation_(initial_generation) {} GlyphAtlas::~GlyphAtlas() = default; @@ -65,10 +67,20 @@ void GlyphAtlas::SetTexture(std::shared_ptr texture) { texture_ = std::move(texture); } +size_t GlyphAtlas::GetAtlasGeneration() const { + return generation_; +} + +void GlyphAtlas::SetAtlasGeneration(size_t generation) { + generation_ = generation; +} + void GlyphAtlas::AddTypefaceGlyphPositionAndBounds(const FontGlyphPair& pair, Rect position, Rect bounds) { - font_atlas_map_[pair.scaled_font].positions_[pair.glyph] = + FontAtlasMap::iterator it = font_atlas_map_.find(pair.scaled_font); + FML_DCHECK(it != font_atlas_map_.end()); + it->second.positions_[pair.glyph] = FrameBounds{position, bounds, /*is_placeholder=*/false}; } @@ -83,12 +95,9 @@ std::optional GlyphAtlas::FindFontGlyphBounds( FontGlyphAtlas* GlyphAtlas::GetOrCreateFontGlyphAtlas( const ScaledFont& scaled_font) { - const auto& found = font_atlas_map_.find(scaled_font); - if (found != font_atlas_map_.end()) { - return &found->second; - } - font_atlas_map_[scaled_font] = FontGlyphAtlas(); - return &font_atlas_map_[scaled_font]; + auto [iter, inserted] = + font_atlas_map_.try_emplace(scaled_font, FontGlyphAtlas()); + return &iter->second; } size_t GlyphAtlas::GetGlyphCount() const { diff --git a/impeller/typographer/glyph_atlas.h b/impeller/typographer/glyph_atlas.h index 87c5490318387..de158bae31c73 100644 --- a/impeller/typographer/glyph_atlas.h +++ b/impeller/typographer/glyph_atlas.h @@ -8,7 +8,16 @@ #include #include #include -#include + +#include "flutter/fml/build_config.h" + +#if defined(OS_FUCHSIA) +// TODO(gaaclarke): Migrate to use absl. I couldn't get it working since absl +// has special logic in its GN files for Fuchsia that I couldn't sort out. +#define IMPELLER_TYPOGRAPHER_USE_STD_HASH +#else +#include "flutter/third_party/abseil-cpp/absl/container/flat_hash_map.h" +#endif #include "impeller/core/texture.h" #include "impeller/geometry/rect.h" @@ -19,6 +28,30 @@ namespace impeller { class FontGlyphAtlas; +/// Helper for AbslHashAdapter. Tallies a hash value with fml::HashCombine. +template +struct AbslHashAdapterCombiner { + std::size_t value = 0; + + template + static AbslHashAdapterCombiner combine(AbslHashAdapterCombiner combiner, + const Args&... args) { + combiner.value = fml::HashCombine(combiner.value, args...); + return combiner; + } +}; + +/// Adapts AbslHashValue functions to be used with std::unordered_map and the +/// fml hash functions. +template +struct AbslHashAdapter { + constexpr std::size_t operator()(const T& element) const { + AbslHashAdapterCombiner combiner; + combiner = AbslHashValue(std::move(combiner), element); + return combiner.value; + } +}; + struct FrameBounds { /// The bounds of the glyph within the glyph atlas. Rect atlas_bounds; @@ -58,8 +91,9 @@ class GlyphAtlas { /// @brief Create an empty glyph atlas. /// /// @param[in] type How the glyphs are represented in the texture. + /// @param[in] initial_generation the atlas generation. /// - explicit GlyphAtlas(Type type); + GlyphAtlas(Type type, size_t initial_generation); ~GlyphAtlas(); @@ -142,15 +176,36 @@ class GlyphAtlas { /// FontGlyphAtlas* GetOrCreateFontGlyphAtlas(const ScaledFont& scaled_font); + //---------------------------------------------------------------------------- + /// @brief Retrieve the generation id for this glyph atlas. + /// + /// The generation id is used to match with a TextFrame to + /// determine if the frame is guaranteed to already be populated + /// in the atlas. + size_t GetAtlasGeneration() const; + + //---------------------------------------------------------------------------- + /// @brief Update the atlas generation. + void SetAtlasGeneration(size_t value); + private: const Type type_; std::shared_ptr texture_; - - std::unordered_map - font_atlas_map_; + size_t generation_ = 0; + +#if defined(IMPELLER_TYPOGRAPHER_USE_STD_HASH) + using FontAtlasMap = std::unordered_map, + ScaledFont::Equal>; +#else + using FontAtlasMap = absl::flat_hash_map, + ScaledFont::Equal>; +#endif + + FontAtlasMap font_atlas_map_; GlyphAtlas(const GlyphAtlas&) = delete; @@ -214,6 +269,7 @@ class GlyphAtlasContext { class FontGlyphAtlas { public: FontGlyphAtlas() = default; + FontGlyphAtlas(FontGlyphAtlas&&) = default; //---------------------------------------------------------------------------- /// @brief Find the location of a glyph in the atlas. @@ -235,12 +291,19 @@ class FontGlyphAtlas { private: friend class GlyphAtlas; - std::unordered_map - positions_; - +#if defined(IMPELLER_TYPOGRAPHER_USE_STD_HASH) + using PositionsMap = std::unordered_map, + SubpixelGlyph::Equal>; +#else + using PositionsMap = absl::flat_hash_map, + SubpixelGlyph::Equal>; +#endif + + PositionsMap positions_; FontGlyphAtlas(const FontGlyphAtlas&) = delete; }; diff --git a/impeller/typographer/rectangle_packer.cc b/impeller/typographer/rectangle_packer.cc index 3ec7464ff7995..f9a7be86c5f59 100644 --- a/impeller/typographer/rectangle_packer.cc +++ b/impeller/typographer/rectangle_packer.cc @@ -5,6 +5,7 @@ #include "impeller/typographer/rectangle_packer.h" #include +#include #include #include "flutter/fml/logging.h" diff --git a/impeller/typographer/rectangle_packer.h b/impeller/typographer/rectangle_packer.h index 817bc6605e070..d8b1e1caf3966 100644 --- a/impeller/typographer/rectangle_packer.h +++ b/impeller/typographer/rectangle_packer.h @@ -9,6 +9,7 @@ #include "impeller/geometry/scalar.h" #include +#include namespace impeller { diff --git a/impeller/typographer/text_frame.cc b/impeller/typographer/text_frame.cc index b72bb621c0583..870ff17821e11 100644 --- a/impeller/typographer/text_frame.cc +++ b/impeller/typographer/text_frame.cc @@ -3,11 +3,25 @@ // found in the LICENSE file. #include "impeller/typographer/text_frame.h" +#include "impeller/geometry/scalar.h" #include "impeller/typographer/font.h" #include "impeller/typographer/font_glyph_pair.h" namespace impeller { +namespace { +static bool TextPropertiesEquals(const std::optional& a, + const std::optional& b) { + if (!a.has_value() && !b.has_value()) { + return true; + } + if (a.has_value() && b.has_value()) { + return GlyphProperties::Equal{}(a.value(), b.value()); + } + return false; +} +} // namespace + TextFrame::TextFrame() = default; TextFrame::TextFrame(std::vector& runs, Rect bounds, bool has_color) @@ -37,7 +51,7 @@ bool TextFrame::HasColor() const { } // static -Scalar TextFrame::RoundScaledFontSize(Scalar scale, Scalar point_size) { +Scalar TextFrame::RoundScaledFontSize(Scalar scale) { // An arbitrarily chosen maximum text scale to ensure that regardless of the // CTM, a glyph will fit in the atlas. If we clamp significantly, this may // reduce fidelity but is preferable to the alternative of failing to render. @@ -87,6 +101,12 @@ Point TextFrame::ComputeSubpixelPosition( void TextFrame::SetPerFrameData(Scalar scale, Point offset, std::optional properties) { + if (!ScalarNearlyEqual(scale_, scale) || + !ScalarNearlyEqual(offset_.x, offset.x) || + !ScalarNearlyEqual(offset_.y, offset.y) || + !TextPropertiesEquals(properties_, properties)) { + bound_values_.clear(); + } scale_ = scale; offset_ = offset; properties_ = properties; @@ -121,7 +141,16 @@ bool TextFrame::IsFrameComplete() const { } const FrameBounds& TextFrame::GetFrameBounds(size_t index) const { - return bound_values_.at(index); + return bound_values_[index]; +} + +std::pair TextFrame::GetAtlasGenerationAndID() const { + return std::make_pair(generation_, atlas_id_); +} + +void TextFrame::SetAtlasGeneration(size_t value, intptr_t atlas_id) { + generation_ = value; + atlas_id_ = atlas_id; } } // namespace impeller diff --git a/impeller/typographer/text_frame.h b/impeller/typographer/text_frame.h index 0604d6cc1eb6b..10a942cbeeb5b 100644 --- a/impeller/typographer/text_frame.h +++ b/impeller/typographer/text_frame.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_IMPELLER_TYPOGRAPHER_TEXT_FRAME_H_ #define FLUTTER_IMPELLER_TYPOGRAPHER_TEXT_FRAME_H_ +#include #include "impeller/typographer/glyph_atlas.h" #include "impeller/typographer/text_run.h" @@ -32,7 +33,7 @@ class TextFrame { Point offset, Scalar scale); - static Scalar RoundScaledFontSize(Scalar scale, Scalar point_size); + static Scalar RoundScaledFontSize(Scalar scale); //---------------------------------------------------------------------------- /// @brief The conservative bounding box for this text frame. @@ -84,13 +85,18 @@ class TextFrame { Point offset, std::optional properties); + // A generation id for the glyph atlas this text run was associated + // with. As long as the frame generation matches the atlas generation, + // the contents are guaranteed to be populated and do not need to be + // processed. + std::pair GetAtlasGenerationAndID() const; + TextFrame& operator=(TextFrame&& other) = default; TextFrame(const TextFrame& other) = default; private: friend class TypographerContextSkia; - friend class TypographerContextSTB; friend class LazyGlyphAtlas; Scalar GetScale() const; @@ -103,14 +109,18 @@ class TextFrame { void ClearFrameBounds(); + void SetAtlasGeneration(size_t value, intptr_t atlas_id); + std::vector runs_; Rect bounds_; bool has_color_; // Data that is cached when rendering the text frame and is only - // valid for a single frame. + // valid for the current atlas generation. std::vector bound_values_; Scalar scale_ = 0; + size_t generation_ = 0; + intptr_t atlas_id_ = 0; Point offset_; std::optional properties_; }; diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index 6367314d9b397..e677cd7c3c329 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -508,7 +508,7 @@ TEST_P(TypographerTest, TextFrameInitialBoundsArePlaceholder) { GetContext()->GetIdleWaiter()); auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer, - GlyphAtlas::Type::kAlphaBitmap, 1.0f, + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f, atlas_context, frame); // The glyph position in the atlas was not known when this value @@ -517,14 +517,144 @@ TEST_P(TypographerTest, TextFrameInitialBoundsArePlaceholder) { EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder); atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer, - GlyphAtlas::Type::kAlphaBitmap, 1.0f, atlas_context, - frame); + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f, + atlas_context, frame); // The second time the glyph is rendered, the bounds are correcly known. EXPECT_TRUE(frame->IsFrameComplete()); EXPECT_FALSE(frame->GetFrameBounds(0).is_placeholder); } +TEST_P(TypographerTest, TextFrameInvalidationWithScale) { + SkFont font = flutter::testing::CreateTestFontOfSize(12); + auto blob = SkTextBlob::MakeFromString( + "the quick brown fox jumped over the lazy dog.", font); + ASSERT_TRUE(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); + + EXPECT_FALSE(frame->IsFrameComplete()); + + auto context = TypographerContextSkia::Make(); + auto atlas_context = + context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap); + auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(), + GetContext()->GetIdleWaiter()); + + auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer, + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f, + atlas_context, frame); + + // The glyph position in the atlas was not known when this value + // was recorded. It is marked as a placeholder. + EXPECT_TRUE(frame->IsFrameComplete()); + EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder); + + // Change the scale and the glyph data will still be a placeholder, as the + // old data is no longer valid. + atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer, + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/2.0f, + atlas_context, frame); + + // The second time the glyph is rendered, the bounds are correcly known. + EXPECT_TRUE(frame->IsFrameComplete()); + EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder); +} + +TEST_P(TypographerTest, TextFrameAtlasGenerationTracksState) { + SkFont font = flutter::testing::CreateTestFontOfSize(12); + auto blob = SkTextBlob::MakeFromString( + "the quick brown fox jumped over the lazy dog.", font); + ASSERT_TRUE(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); + + EXPECT_FALSE(frame->IsFrameComplete()); + + auto context = TypographerContextSkia::Make(); + auto atlas_context = + context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap); + auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(), + GetContext()->GetIdleWaiter()); + + auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer, + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f, + atlas_context, frame); + + // The glyph position in the atlas was not known when this value + // was recorded. It is marked as a placeholder. + EXPECT_TRUE(frame->IsFrameComplete()); + EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder); + if (GetBackend() == PlaygroundBackend::kOpenGLES) { + // OpenGLES must always increase the atlas backend if the texture grows. + EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u); + } else { + EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u); + } + + atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer, + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f, + atlas_context, frame); + + // The second time the glyph is rendered, the bounds are correcly known. + EXPECT_TRUE(frame->IsFrameComplete()); + EXPECT_FALSE(frame->GetFrameBounds(0).is_placeholder); + if (GetBackend() == PlaygroundBackend::kOpenGLES) { + EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u); + } else { + EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u); + } + + // Force increase the generation. + atlas_context->GetGlyphAtlas()->SetAtlasGeneration(2u); + atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer, + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f, + atlas_context, frame); + + EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 2u); +} + +TEST_P(TypographerTest, InvalidAtlasForcesRepopulation) { + SkFont font = flutter::testing::CreateTestFontOfSize(12); + auto blob = SkTextBlob::MakeFromString( + "the quick brown fox jumped over the lazy dog.", font); + ASSERT_TRUE(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); + + EXPECT_FALSE(frame->IsFrameComplete()); + + auto context = TypographerContextSkia::Make(); + auto atlas_context = + context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap); + auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(), + GetContext()->GetIdleWaiter()); + + auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer, + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f, + atlas_context, frame); + + // The glyph position in the atlas was not known when this value + // was recorded. It is marked as a placeholder. + EXPECT_TRUE(frame->IsFrameComplete()); + EXPECT_TRUE(frame->GetFrameBounds(0).is_placeholder); + if (GetBackend() == PlaygroundBackend::kOpenGLES) { + // OpenGLES must always increase the atlas backend if the texture grows. + EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 1u); + } else { + EXPECT_EQ(frame->GetAtlasGenerationAndID().first, 0u); + } + + auto second_context = TypographerContextSkia::Make(); + auto second_atlas_context = + second_context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap); + + EXPECT_FALSE(second_atlas_context->GetGlyphAtlas()->IsValid()); + + atlas = CreateGlyphAtlas(*GetContext(), second_context.get(), *host_buffer, + GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f, + second_atlas_context, frame); + + EXPECT_TRUE(second_atlas_context->GetGlyphAtlas()->IsValid()); +} + } // namespace testing } // namespace impeller diff --git a/lib/gpu/pubspec.yaml b/lib/gpu/pubspec.yaml index 910d8f816abe6..3406760324cbe 100644 --- a/lib/gpu/pubspec.yaml +++ b/lib/gpu/pubspec.yaml @@ -8,7 +8,7 @@ homepage: https://flutter.dev repository: https://github.com/flutter/engine/tree/main/lib/gpu environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/lib/gpu/render_pass.cc b/lib/gpu/render_pass.cc index 3987d823f5a22..b2f43bc2db187 100644 --- a/lib/gpu/render_pass.cc +++ b/lib/gpu/render_pass.cc @@ -105,10 +105,13 @@ RenderPass::GetOrCreatePipeline() { pipeline_desc.SetSampleCount(render_target_.GetSampleCount()); - for (const auto& it : render_target_.GetColorAttachments()) { - auto& color = GetColorAttachmentDescriptor(it.first); - color.format = render_target_.GetRenderTargetPixelFormat(); - } + render_target_.IterateAllColorAttachments( + [&](size_t index, const impeller::ColorAttachment& attachment) -> bool { + auto& color = GetColorAttachmentDescriptor(index); + color.format = render_target_.GetRenderTargetPixelFormat(); + return true; + }); + pipeline_desc.SetColorAttachmentDescriptors(color_descriptors_); { @@ -177,28 +180,34 @@ bool RenderPass::Draw() { render_pass_->SetPipeline(GetOrCreatePipeline()); for (const auto& [_, buffer] : vertex_uniform_bindings) { - render_pass_->BindResource(impeller::ShaderStage::kVertex, - impeller::DescriptorType::kUniformBuffer, - buffer.slot, *buffer.view.GetMetadata(), - buffer.view.resource); + render_pass_->BindDynamicResource( + impeller::ShaderStage::kVertex, + impeller::DescriptorType::kUniformBuffer, buffer.slot, + std::make_unique(*buffer.view.GetMetadata()), + buffer.view.resource); } for (const auto& [_, texture] : vertex_texture_bindings) { - render_pass_->BindResource(impeller::ShaderStage::kVertex, - impeller::DescriptorType::kSampledImage, - texture.slot, *texture.texture.GetMetadata(), - texture.texture.resource, *texture.sampler); + render_pass_->BindDynamicResource( + impeller::ShaderStage::kVertex, impeller::DescriptorType::kSampledImage, + texture.slot, + std::make_unique( + *texture.texture.GetMetadata()), + texture.texture.resource, *texture.sampler); } for (const auto& [_, buffer] : fragment_uniform_bindings) { - render_pass_->BindResource(impeller::ShaderStage::kFragment, - impeller::DescriptorType::kUniformBuffer, - buffer.slot, *buffer.view.GetMetadata(), - buffer.view.resource); + render_pass_->BindDynamicResource( + impeller::ShaderStage::kFragment, + impeller::DescriptorType::kUniformBuffer, buffer.slot, + std::make_unique(*buffer.view.GetMetadata()), + buffer.view.resource); } for (const auto& [_, texture] : fragment_texture_bindings) { - render_pass_->BindResource(impeller::ShaderStage::kFragment, - impeller::DescriptorType::kSampledImage, - texture.slot, *texture.texture.GetMetadata(), - texture.texture.resource, *texture.sampler); + render_pass_->BindDynamicResource( + impeller::ShaderStage::kFragment, + impeller::DescriptorType::kSampledImage, texture.slot, + std::make_unique( + *texture.texture.GetMetadata()), + texture.texture.resource, *texture.sampler); } render_pass_->SetVertexBuffer(vertex_buffer); @@ -408,7 +417,7 @@ static bool BindUniform( uniform_map->insert_or_assign( uniform_struct, - impeller::BufferAndUniformSlot{ + flutter::gpu::RenderPass::BufferAndUniformSlot{ .slot = uniform_struct->slot, .view = impeller::BufferResource{ &uniform_struct->metadata, diff --git a/lib/gpu/render_pass.h b/lib/gpu/render_pass.h index 08dd2ee902b4c..5c540f761817b 100644 --- a/lib/gpu/render_pass.h +++ b/lib/gpu/render_pass.h @@ -13,6 +13,7 @@ #include "flutter/lib/ui/dart_wrapper.h" #include "fml/memory/ref_ptr.h" #include "impeller/core/formats.h" +#include "impeller/core/shader_types.h" #include "impeller/renderer/command.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" @@ -56,9 +57,14 @@ class RenderPass : public RefCountedDartWrappable { bool Draw(); + struct BufferAndUniformSlot { + impeller::ShaderUniformSlot slot; + impeller::BufferResource view; + }; + using BufferUniformMap = std::unordered_map; + BufferAndUniformSlot>; using TextureUniformMap = std::unordered_map; diff --git a/lib/snapshot/pubspec.yaml b/lib/snapshot/pubspec.yaml index cba35438d9020..79c7060370a6a 100644 --- a/lib/snapshot/pubspec.yaml +++ b/lib/snapshot/pubspec.yaml @@ -6,4 +6,4 @@ name: _snapshot_but_this_package_name_is_not_used environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/lib/ui/fixtures/out_of_bounds.apng b/lib/ui/fixtures/out_of_bounds.apng new file mode 100644 index 0000000000000..33993c7960e96 Binary files /dev/null and b/lib/ui/fixtures/out_of_bounds.apng differ diff --git a/lib/ui/fixtures/out_of_bounds_wrapping.apng b/lib/ui/fixtures/out_of_bounds_wrapping.apng new file mode 100644 index 0000000000000..e4cc5d50cfe5f Binary files /dev/null and b/lib/ui/fixtures/out_of_bounds_wrapping.apng differ diff --git a/lib/ui/painting/color_filter.cc b/lib/ui/painting/color_filter.cc index f0d780d27208d..e58cb659209c0 100644 --- a/lib/ui/painting/color_filter.cc +++ b/lib/ui/painting/color_filter.cc @@ -23,7 +23,7 @@ void ColorFilter::Create(Dart_Handle wrapper) { } void ColorFilter::initMode(int color, int blend_mode) { - filter_ = DlBlendColorFilter::Make(static_cast(color), + filter_ = DlColorFilter::MakeBlend(static_cast(color), static_cast(blend_mode)); } @@ -39,15 +39,15 @@ void ColorFilter::initMatrix(const tonic::Float32List& color_matrix) { matrix[9] *= 1.0f / 255; matrix[14] *= 1.0f / 255; matrix[19] *= 1.0f / 255; - filter_ = DlMatrixColorFilter::Make(matrix); + filter_ = DlColorFilter::MakeMatrix(matrix); } void ColorFilter::initLinearToSrgbGamma() { - filter_ = DlLinearToSrgbGammaColorFilter::kInstance; + filter_ = DlColorFilter::MakeLinearToSrgbGamma(); } void ColorFilter::initSrgbToLinearGamma() { - filter_ = DlSrgbToLinearGammaColorFilter::kInstance; + filter_ = DlColorFilter::MakeSrgbToLinearGamma(); } ColorFilter::~ColorFilter() = default; diff --git a/lib/ui/painting/fragment_program.cc b/lib/ui/painting/fragment_program.cc index 68a96a15247af..54b321609c08e 100644 --- a/lib/ui/painting/fragment_program.cc +++ b/lib/ui/painting/fragment_program.cc @@ -33,6 +33,8 @@ static std::string RuntimeStageBackendToString( return "OpenGLES"; case impeller::RuntimeStageBackend::kVulkan: return "Vulkan"; + case impeller::RuntimeStageBackend::kOpenGLES3: + return "OpenGLES3"; } } diff --git a/lib/ui/painting/image_decoder_no_gl_unittests.cc b/lib/ui/painting/image_decoder_no_gl_unittests.cc index 04a0229c112dd..aad5032952ea2 100644 --- a/lib/ui/painting/image_decoder_no_gl_unittests.cc +++ b/lib/ui/painting/image_decoder_no_gl_unittests.cc @@ -197,7 +197,7 @@ TEST(ImageDecoderNoGLTest, ImpellerWideGamutIndexedPng) { #endif // IMPELLER_SUPPORTS_RENDERING } -TEST(ImageDecoderNoGLTest, ImepllerUnmultipliedAlphaPng) { +TEST(ImageDecoderNoGLTest, ImpellerUnmultipliedAlphaPng) { #if defined(OS_FUCHSIA) GTEST_SKIP() << "Fuchsia can't load the test fixtures."; #endif diff --git a/lib/ui/painting/image_decoder_unittests.cc b/lib/ui/painting/image_decoder_unittests.cc index 1e41ab5cc82e3..968c09d3446c7 100644 --- a/lib/ui/painting/image_decoder_unittests.cc +++ b/lib/ui/painting/image_decoder_unittests.cc @@ -24,6 +24,7 @@ #include "flutter/testing/test_gl_surface.h" #include "flutter/testing/testing.h" #include "fml/logging.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/command_queue.h" #include "third_party/skia/include/codec/SkCodecAnimation.h" #include "third_party/skia/include/core/SkData.h" @@ -96,6 +97,10 @@ class TestImpellerContext : public impeller::Context { void Shutdown() override {} + RuntimeStageBackend GetRuntimeStageBackend() const override { + return RuntimeStageBackend::kVulkan; + } + bool DidDisposeResources() const { return did_dispose_; } mutable size_t command_buffer_count_ = 0; diff --git a/lib/ui/painting/image_generator_apng.cc b/lib/ui/painting/image_generator_apng.cc index 159d87638aeb2..08182c9ff2bd4 100644 --- a/lib/ui/painting/image_generator_apng.cc +++ b/lib/ui/painting/image_generator_apng.cc @@ -110,6 +110,28 @@ bool APNGImageGenerator::GetPixels(const SkImageInfo& info, << ") of APNG due to the frame missing data (frame_info)."; return false; } + if ( + // Check for unsigned integer wrapping for + // frame.{x|y}_offset + frame_info.{width|height}(). + frame.x_offset > + std::numeric_limits::max() - frame_info.width() || + frame.y_offset > + std::numeric_limits::max() - frame_info.height() || + + frame.x_offset + frame_info.width() > + static_cast(info.width()) || + frame.y_offset + frame_info.height() > + static_cast(info.height())) { + FML_DLOG(ERROR) + << "Decoded image at index " << image_index + << " (frame index: " << frame_index + << ") rejected because the destination region (x: " << frame.x_offset + << ", y: " << frame.y_offset << ", width: " << frame_info.width() + << ", height: " << frame_info.height() + << ") is not entirely within the destination surface (width: " + << info.width() << ", height: " << info.height() << ")."; + return false; + } //---------------------------------------------------------------------------- /// 3. Composite the frame onto the canvas. @@ -630,7 +652,19 @@ uint32_t APNGImageGenerator::ChunkHeader::ComputeChunkCrc32() { bool APNGImageGenerator::RenderDefaultImage(const SkImageInfo& info, void* pixels, size_t row_bytes) { - SkCodec::Result result = images_[0].codec->getPixels(info, pixels, row_bytes); + APNGImage& frame = images_[0]; + SkImageInfo frame_info = frame.codec->getInfo(); + if (frame_info.width() > info.width() || + frame_info.height() > info.height()) { + FML_DLOG(ERROR) + << "Default image rejected because the destination region (width: " + << frame_info.width() << ", height: " << frame_info.height() + << ") is not entirely within the destination surface (width: " + << info.width() << ", height: " << info.height() << ")."; + return false; + } + + SkCodec::Result result = frame.codec->getPixels(info, pixels, row_bytes); if (result != SkCodec::kSuccess) { FML_DLOG(ERROR) << "Failed to decode the APNG's default/fallback image. " "SkCodec::Result: " diff --git a/lib/ui/painting/paint_unittests.cc b/lib/ui/painting/paint_unittests.cc index 2b051f00b0da0..9d18dbed43bde 100644 --- a/lib/ui/painting/paint_unittests.cc +++ b/lib/ui/painting/paint_unittests.cc @@ -52,7 +52,7 @@ TEST_F(ShellTest, ConvertPaintToDlPaint) { ASSERT_EQ(dl_paint.getBlendMode(), DlBlendMode::kModulate); ASSERT_EQ(static_cast(dl_paint.getColor().argb()), 0x11223344u); ASSERT_EQ(*dl_paint.getColorFilter(), - DlBlendColorFilter(DlColor(0x55667788), DlBlendMode::kXor)); + *DlColorFilter::MakeBlend(DlColor(0x55667788), DlBlendMode::kXor)); ASSERT_EQ(*dl_paint.getMaskFilter(), DlBlurMaskFilter(DlBlurStyle::kInner, 0.75)); ASSERT_EQ(dl_paint.getDrawStyle(), DlDrawStyle::kStroke); diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index bb9d586e41e54..59052b157b687 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -45,6 +45,7 @@ class SemanticsAction { static const int _kMoveCursorBackwardByWordIndex = 1 << 20; static const int _kSetTextIndex = 1 << 21; static const int _kFocusIndex = 1 << 22; + static const int _kScrollToOffsetIndex = 1 << 23; // READ THIS: if you add an action here, you MUST update the // numSemanticsActions value in testing/dart/semantics_test.dart and // lib/web_ui/test/engine/semantics/semantics_api_test.dart, or tests @@ -86,6 +87,17 @@ class SemanticsAction { /// scrollable. static const SemanticsAction scrollDown = SemanticsAction._(_kScrollDownIndex, 'scrollDown'); + /// A request to scroll the scrollable container to a given scroll offset. + /// + /// The payload of this [SemanticsAction] is a flutter-standard-encoded + /// [Float64List] of length 2 containing the target horizontal and vertical + /// offsets (in logical pixels) the receiving scrollable container should + /// scroll to. + /// + /// This action is used by iOS Full Keyboard Access to reveal contents that + /// are currently not visible in the viewport. + static const SemanticsAction scrollToOffset = SemanticsAction._(_kScrollToOffsetIndex, 'scrollToOffset'); + /// A request to increase the value represented by the semantics node. /// /// For example, this action might be recognized by a slider control. @@ -265,6 +277,7 @@ class SemanticsAction { _kScrollRightIndex: scrollRight, _kScrollUpIndex: scrollUp, _kScrollDownIndex: scrollDown, + _kScrollToOffsetIndex: scrollToOffset, _kIncreaseIndex: increase, _kDecreaseIndex: decrease, _kShowOnScreenIndex: showOnScreen, @@ -764,7 +777,7 @@ base class LocaleStringAttribute extends StringAttribute { _initLocaleStringAttribute(this, range.start, range.end, locale.toLanguageTag()); } - /// The lanuage of this attribute. + /// The language of this attribute. final Locale locale; @Native(symbol: 'NativeStringAttribute::initLocaleStringAttribute') diff --git a/lib/ui/semantics/semantics_node.h b/lib/ui/semantics/semantics_node.h index 98d84c6c6aebb..0f02ff3202f18 100644 --- a/lib/ui/semantics/semantics_node.h +++ b/lib/ui/semantics/semantics_node.h @@ -43,6 +43,7 @@ enum class SemanticsAction : int32_t { kMoveCursorBackwardByWord = 1 << 20, kSetText = 1 << 21, kFocus = 1 << 22, + kScrollToOffset = 1 << 23, }; const int kVerticalScrollSemanticsActions = diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index be36411520314..786eaacc5454f 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -33,6 +33,7 @@ class SemanticsAction { static const int _kMoveCursorBackwardByWordIndex = 1 << 20; static const int _kSetTextIndex = 1 << 21; static const int _kFocusIndex = 1 << 22; + static const int _kScrollToOffsetIndex = 1 << 23; static const SemanticsAction tap = SemanticsAction._(_kTapIndex, 'tap'); static const SemanticsAction longPress = SemanticsAction._(_kLongPressIndex, 'longPress'); @@ -40,6 +41,7 @@ class SemanticsAction { static const SemanticsAction scrollRight = SemanticsAction._(_kScrollRightIndex, 'scrollRight'); static const SemanticsAction scrollUp = SemanticsAction._(_kScrollUpIndex, 'scrollUp'); static const SemanticsAction scrollDown = SemanticsAction._(_kScrollDownIndex, 'scrollDown'); + static const SemanticsAction scrollToOffset = SemanticsAction._(_kScrollToOffsetIndex, 'scrollToOffset'); static const SemanticsAction increase = SemanticsAction._(_kIncreaseIndex, 'increase'); static const SemanticsAction decrease = SemanticsAction._(_kDecreaseIndex, 'decrease'); static const SemanticsAction showOnScreen = SemanticsAction._(_kShowOnScreenIndex, 'showOnScreen'); @@ -65,6 +67,7 @@ class SemanticsAction { _kScrollRightIndex: scrollRight, _kScrollUpIndex: scrollUp, _kScrollDownIndex: scrollDown, + _kScrollToOffsetIndex: scrollToOffset, _kIncreaseIndex: increase, _kDecreaseIndex: decrease, _kShowOnScreenIndex: showOnScreen, diff --git a/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart b/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart index 494f940d58eb4..82954325ab85e 100644 --- a/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart +++ b/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart @@ -18,9 +18,12 @@ import '../window.dart'; /// The offset is *not* multiplied by DPR or anything else, it's the closest /// to what the DOM would return if we had currentTarget readily available. /// -/// This needs an `eventTarget`, because the `event.target` (which is what -/// this would really need to use) gets lost when the `event` comes from a -/// "coalesced" event (see https://github.com/flutter/flutter/issues/155987). +/// This takes an optional `eventTarget`, because the `event.target` may have +/// the wrong value for "coalesced" events. See: +/// +/// - https://github.com/flutter/flutter/issues/155987 +/// - https://github.com/flutter/flutter/issues/159804 +/// - https://g-issues.chromium.org/issues/382473107 /// /// It also takes into account semantics being enabled to fix the case where /// offsetX, offsetY == 0 (TalkBack events). @@ -41,12 +44,12 @@ ui.Offset computeEventOffsetToTarget( if (isInput) { final EditableTextGeometry? inputGeometry = textEditing.strategy.geometry; if (inputGeometry != null) { - return _computeOffsetForInputs(event, inputGeometry); + return _computeOffsetForInputs(event, eventTarget, inputGeometry); } } // On another DOM Element (normally a platform view) - final bool isTargetOutsideOfShadowDOM = event.target != actualTarget; + final bool isTargetOutsideOfShadowDOM = eventTarget != actualTarget; if (isTargetOutsideOfShadowDOM) { final DomRect origin = actualTarget.getBoundingClientRect(); // event.clientX/Y and origin.x/y are relative **to the viewport**. @@ -70,8 +73,14 @@ ui.Offset computeEventOffsetToTarget( /// sent from the framework, which includes information on how to transform the /// underlying input element. We transform the `event.offset` points we receive /// using the values from the input's transform matrix. -ui.Offset _computeOffsetForInputs(DomMouseEvent event, EditableTextGeometry inputGeometry) { - final DomElement targetElement = event.target! as DomHTMLElement; +/// +/// See [computeEventOffsetToTarget] for more information about `eventTarget`. +ui.Offset _computeOffsetForInputs( + DomMouseEvent event, + DomEventTarget eventTarget, + EditableTextGeometry inputGeometry, +) { + final DomElement targetElement = eventTarget as DomElement; final DomHTMLElement domElement = textEditing.strategy.activeDomElement; assert(targetElement == domElement, 'The targeted input element must be the active input element'); final Float32List transformValues = inputGeometry.globalTransform; diff --git a/lib/web_ui/pubspec.yaml b/lib/web_ui/pubspec.yaml index b391eab26a713..06f585c97dedd 100644 --- a/lib/web_ui/pubspec.yaml +++ b/lib/web_ui/pubspec.yaml @@ -3,7 +3,7 @@ publish_to: none # Keep the SDK version range in sync with pubspecs under web_sdk environment: - sdk: '>=3.6.0-0 <4.0.0' + sdk: ^3.7.0-0 dependencies: js: ^0.7.0 diff --git a/lib/web_ui/test/engine/pointer_binding/event_position_helper_test.dart b/lib/web_ui/test/engine/pointer_binding/event_position_helper_test.dart index eca204cd6e613..14f41dccbbf9a 100644 --- a/lib/web_ui/test/engine/pointer_binding/event_position_helper_test.dart +++ b/lib/web_ui/test/engine/pointer_binding/event_position_helper_test.dart @@ -32,6 +32,7 @@ void doTests() { group('computeEventOffsetToTarget', () { setUp(() { view = EngineFlutterView(EnginePlatformDispatcher.instance, domDocument.body!); + EnginePlatformDispatcher.instance.viewManager.registerView(view); rootElement = view.dom.rootElement; eventSource = createDomElement('div-event-source'); rootElement.append(eventSource); @@ -58,6 +59,7 @@ void doTests() { }); tearDown(() { + EnginePlatformDispatcher.instance.viewManager.unregisterView(view.viewId); view.dispose(); }); @@ -101,6 +103,36 @@ void doTests() { expect(offset.dy, 110); }); + test('eventTarget takes precedence', () async { + final input = view.dom.textEditingHost.appendChild(createDomElement('input')); + + textEditing.strategy.enable( + InputConfiguration(viewId: view.viewId), + onChange: (_, __) {}, + onAction: (_) {}, + ); + + addTearDown(() { + textEditing.strategy.disable(); + }); + + final moveEvent = createDomPointerEvent('pointermove', { + 'bubbles': true, + 'clientX': 10, + 'clientY': 20, + }); + + expect( + () => computeEventOffsetToTarget(moveEvent, view), + throwsA(anything), + ); + + expect( + () => computeEventOffsetToTarget(moveEvent, view, eventTarget: input), + returnsNormally, + ); + }); + test('Event dispatched by TalkBack gets a computed offset', () async { // Fill this in to test _computeOffsetForTalkbackEvent }, skip: 'To be implemented!'); diff --git a/lib/web_ui/test/engine/semantics/semantics_api_test.dart b/lib/web_ui/test/engine/semantics/semantics_api_test.dart index 8df41a7cae384..e56242639b44c 100644 --- a/lib/web_ui/test/engine/semantics/semantics_api_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_api_test.dart @@ -29,7 +29,7 @@ void testMain() { }); // This must match the number of actions in lib/ui/semantics.dart - const int numSemanticsActions = 23; + const int numSemanticsActions = 24; test('SemanticsAction.values refers to all actions.', () async { expect(SemanticsAction.values.length, equals(numSemanticsActions)); for (int index = 0; index < numSemanticsActions; ++index) { diff --git a/pubspec.yaml b/pubspec.yaml index 4646a95639cf0..0eb81c032e285 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,7 +35,7 @@ # # # Required for workspace support. # environment: -# sdk: ^3.5.0-294.0.dev +# sdk: ^3.7.0-0 # # # This package is managed as part of the engine workspace. # resolution: workspace @@ -76,7 +76,7 @@ name: _engine_workspace # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # Declare all packages that are part of the workspace. workspace: diff --git a/runtime/dart_service_isolate.h b/runtime/dart_service_isolate.h index a6fc32d4297af..439b49ce5884c 100644 --- a/runtime/dart_service_isolate.h +++ b/runtime/dart_service_isolate.h @@ -6,6 +6,7 @@ #define FLUTTER_RUNTIME_DART_SERVICE_ISOLATE_H_ #include +#include #include #include #include diff --git a/shell/common/dl_op_spy.cc b/shell/common/dl_op_spy.cc index 5c109bee314f1..f9671ccab4a73 100644 --- a/shell/common/dl_op_spy.cc +++ b/shell/common/dl_op_spy.cc @@ -4,8 +4,6 @@ #include "flutter/shell/common/dl_op_spy.h" -#include "flutter/display_list/effects/color_sources/dl_color_color_source.h" - namespace flutter { bool DlOpSpy::did_draw() { @@ -13,6 +11,7 @@ bool DlOpSpy::did_draw() { } void DlOpSpy::setColor(DlColor color) { + color_ = color; if (color.isTransparent()) { will_draw_ = false; } else { @@ -21,11 +20,8 @@ void DlOpSpy::setColor(DlColor color) { } void DlOpSpy::setColorSource(const DlColorSource* source) { if (!source) { - return; - } - const DlColorColorSource* color_source = source->asColor(); - if (color_source && color_source->color().isTransparent()) { - will_draw_ = false; + // Restore settings based on previously set color + setColor(color_); return; } will_draw_ = true; diff --git a/shell/common/dl_op_spy.h b/shell/common/dl_op_spy.h index 3c2c63d75f8c9..27fe39554f3b5 100644 --- a/shell/common/dl_op_spy.h +++ b/shell/common/dl_op_spy.h @@ -106,6 +106,9 @@ class DlOpSpy final : public virtual DlOpReceiver, bool transparent_occluder, DlScalar dpr) override; + // Most recently set color, used when color_source goes to null + DlColor color_; + // Indicates if the attributes are set to values that will modify the // destination. For now, the test only checks if there is a non-transparent // color set. diff --git a/shell/common/dl_op_spy_unittests.cc b/shell/common/dl_op_spy_unittests.cc index b04c6d6f176f1..8dc48734da129 100644 --- a/shell/common/dl_op_spy_unittests.cc +++ b/shell/common/dl_op_spy_unittests.cc @@ -84,29 +84,26 @@ TEST(DlOpSpy, SetColorSource) { dl->Dispatch(dl_op_spy); ASSERT_DID_DRAW(dl_op_spy, dl); } - { // Set transparent color. - DisplayListBuilder builder; - DlPaint paint; - auto color = DlColor::kTransparent(); - DlColorColorSource color_source_transparent(color); - paint.setColorSource(color_source_transparent.shared()); - builder.DrawRect(SkRect::MakeWH(5, 5), paint); - sk_sp dl = builder.Build(); + { // setColorSource(null) restores previous color visibility DlOpSpy dl_op_spy; - dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); - } - { // Set black color. - DisplayListBuilder builder; - DlPaint paint; - auto color = DlColor::kBlack(); - DlColorColorSource color_source_transparent(color); - paint.setColorSource(color_source_transparent.shared()); - builder.DrawRect(SkRect::MakeWH(5, 5), paint); - sk_sp dl = builder.Build(); - DlOpSpy dl_op_spy; - dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + DlOpReceiver* receiver = &dl_op_spy; + receiver->setColor(DlColor::kTransparent()); + receiver->drawRect(DlRect::MakeWH(5, 5)); + ASSERT_FALSE(dl_op_spy.did_draw()); + DlColor colors[2] = { + DlColor::kGreen(), + DlColor::kBlue(), + }; + float stops[2] = { + 0.0f, + 1.0f, + }; + auto color_source = DlColorSource::MakeLinear({0, 0}, {10, 10}, 2, colors, + stops, DlTileMode::kClamp); + receiver->setColorSource(color_source.get()); + receiver->setColorSource(nullptr); + receiver->drawRect(DlRect::MakeWH(5, 5)); + ASSERT_FALSE(dl_op_spy.did_draw()); } } diff --git a/shell/common/fixtures/shell_test.dart b/shell/common/fixtures/shell_test.dart index 60727567e5737..24dc227aa8f40 100644 --- a/shell/common/fixtures/shell_test.dart +++ b/shell/common/fixtures/shell_test.dart @@ -640,3 +640,13 @@ void testSemanticsActions() { }); }; } + +@pragma('vm:entry-point') +void testPointerActions() { + PlatformDispatcher.instance.onPointerDataPacket = (PointerDataPacket pointer) async { + await null; + Future.value().then((_) { + notifyNative(); + }); + }; +} diff --git a/shell/common/shell.cc b/shell/common/shell.cc index c6078f78c7de6..9cc5c13f3199b 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "fml/task_runner.h" #define RAPIDJSON_HAS_STDSTRING 1 #include "flutter/shell/common/shell.h" @@ -28,7 +29,6 @@ #include "flutter/shell/common/skia_event_tracer_impl.h" #include "flutter/shell/common/switches.h" #include "flutter/shell/common/vsync_waiter.h" -#include "impeller/runtime_stage/runtime_stage.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" #include "third_party/dart/runtime/include/dart_tools_api.h" @@ -199,14 +199,7 @@ static impeller::RuntimeStageBackend DetermineRuntimeStageBackend( if (!impeller_context) { return impeller::RuntimeStageBackend::kSkSL; } - switch (impeller_context->GetBackendType()) { - case impeller::Context::BackendType::kMetal: - return impeller::RuntimeStageBackend::kMetal; - case impeller::Context::BackendType::kOpenGLES: - return impeller::RuntimeStageBackend::kOpenGLES; - case impeller::Context::BackendType::kVulkan: - return impeller::RuntimeStageBackend::kVulkan; - } + return impeller_context->GetRuntimeStageBackend(); } std::unique_ptr Shell::CreateShellOnPlatformThread( @@ -1036,7 +1029,7 @@ void Shell::OnPlatformViewSetViewportMetrics(int64_t view_id, } }); - fml::TaskRunner::RunNowOrPostTask( + fml::TaskRunner::RunNowAndFlushMessages( task_runners_.GetUITaskRunner(), [engine = engine_->GetWeakPtr(), view_id, metrics]() { if (engine) { @@ -1075,24 +1068,16 @@ void Shell::OnPlatformViewDispatchPlatformMessage( } #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - if (task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()) { - engine_->DispatchPlatformMessage(std::move(message)); - - // Post an empty task to make the UI message loop run its task observers. - // The observers will execute any Dart microtasks queued by the platform - // message handler. - task_runners_.GetUITaskRunner()->PostTask([] {}); - } else { - // The static leak checker gets confused by the use of fml::MakeCopyable. - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - task_runners_.GetUITaskRunner()->PostTask( - fml::MakeCopyable([engine = engine_->GetWeakPtr(), - message = std::move(message)]() mutable { - if (engine) { - engine->DispatchPlatformMessage(std::move(message)); - } - })); - } + // The static leak checker gets confused by the use of fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + fml::TaskRunner::RunNowAndFlushMessages( + task_runners_.GetUITaskRunner(), + fml::MakeCopyable([engine = engine_->GetWeakPtr(), + message = std::move(message)]() mutable { + if (engine) { + engine->DispatchPlatformMessage(std::move(message)); + } + })); } // |PlatformView::Delegate| @@ -1104,7 +1089,7 @@ void Shell::OnPlatformViewDispatchPointerDataPacket( TRACE_FLOW_BEGIN("flutter", "PointerEvent", next_pointer_flow_id_); FML_DCHECK(is_set_up_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - fml::TaskRunner::RunNowOrPostTask( + fml::TaskRunner::RunNowAndFlushMessages( task_runners_.GetUITaskRunner(), fml::MakeCopyable([engine = weak_engine_, packet = std::move(packet), flow_id = next_pointer_flow_id_]() mutable { @@ -1122,7 +1107,8 @@ void Shell::OnPlatformViewDispatchSemanticsAction(int32_t node_id, FML_DCHECK(is_set_up_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - task_runners_.GetUITaskRunner()->PostTask( + fml::TaskRunner::RunNowAndFlushMessages( + task_runners_.GetUITaskRunner(), fml::MakeCopyable([engine = engine_->GetWeakPtr(), node_id, action, args = std::move(args)]() mutable { if (engine) { @@ -1136,12 +1122,13 @@ void Shell::OnPlatformViewSetSemanticsEnabled(bool enabled) { FML_DCHECK(is_set_up_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), - [engine = engine_->GetWeakPtr(), enabled] { - if (engine) { - engine->SetSemanticsEnabled(enabled); - } - }); + fml::TaskRunner::RunNowAndFlushMessages( + task_runners_.GetUITaskRunner(), + [engine = engine_->GetWeakPtr(), enabled] { + if (engine) { + engine->SetSemanticsEnabled(enabled); + } + }); } // |PlatformView::Delegate| @@ -1149,12 +1136,12 @@ void Shell::OnPlatformViewSetAccessibilityFeatures(int32_t flags) { FML_DCHECK(is_set_up_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), - [engine = engine_->GetWeakPtr(), flags] { - if (engine) { - engine->SetAccessibilityFeatures(flags); - } - }); + fml::TaskRunner::RunNowAndFlushMessages( + task_runners_.GetUITaskRunner(), [engine = engine_->GetWeakPtr(), flags] { + if (engine) { + engine->SetAccessibilityFeatures(flags); + } + }); } // |PlatformView::Delegate| diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index ba56e9fb57944..a38994120cba2 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -4312,7 +4312,8 @@ TEST_F(ShellTest, NavigationMessageDispachedImmediately) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } -TEST_F(ShellTest, SemanticsActionsPostTask) { +// Verifies a semantics Action will flush the dart event loop. +TEST_F(ShellTest, SemanticsActionsFlushMessageLoop) { Settings settings = CreateSettingsForFixture(); ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", ThreadHost::Type::kPlatform); @@ -4327,13 +4328,40 @@ TEST_F(ShellTest, SemanticsActionsPostTask) { configuration.SetEntrypoint("testSemanticsActions"); RunEngine(shell.get(), std::move(configuration)); + fml::CountDownLatch latch(1); + AddNativeCallback( + // The Dart native function names aren't very consistent but this is + // just the native function name of the second vm entrypoint in the + // fixture. + "NotifyNative", + CREATE_NATIVE_ENTRY([&](auto args) { latch.CountDown(); })); task_runners.GetPlatformTaskRunner()->PostTask([&] { SendSemanticsAction(shell.get(), 0, SemanticsAction::kTap, fml::MallocMapping(nullptr, 0)); }); + latch.Wait(); - // Fulfill native function for the second Shell's entrypoint. + DestroyShell(std::move(shell), task_runners); + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); +} + +// Verifies a pointer event will flush the dart event loop. +TEST_F(ShellTest, PointerPacketFlushMessageLoop) { + Settings settings = CreateSettingsForFixture(); + ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::kPlatform); + auto task_runner = thread_host.platform_thread->GetTaskRunner(); + TaskRunners task_runners("test", task_runner, task_runner, task_runner, + task_runner); + + EXPECT_EQ(task_runners.GetPlatformTaskRunner(), + task_runners.GetUITaskRunner()); + auto shell = CreateShell(settings, task_runners); + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("testPointerActions"); + + RunEngine(shell.get(), std::move(configuration)); fml::CountDownLatch latch(1); AddNativeCallback( // The Dart native function names aren't very consistent but this is @@ -4341,6 +4369,8 @@ TEST_F(ShellTest, SemanticsActionsPostTask) { // fixture. "NotifyNative", CREATE_NATIVE_ENTRY([&](auto args) { latch.CountDown(); })); + + DispatchFakePointerData(shell.get(), 23); latch.Wait(); DestroyShell(std::move(shell), task_runners); @@ -4846,7 +4876,7 @@ TEST_F(ShellTest, RuntimeStageBackendWithImpeller) { EXPECT_EQ(backend, impeller::RuntimeStageBackend::kMetal); break; case impeller::Context::BackendType::kOpenGLES: - EXPECT_EQ(backend, impeller::RuntimeStageBackend::kOpenGLES); + EXPECT_EQ(backend, impeller::RuntimeStageBackend::kOpenGLES3); break; case impeller::Context::BackendType::kVulkan: EXPECT_EQ(backend, impeller::RuntimeStageBackend::kVulkan); diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index 80074fa3ef982..fdc8c648466e9 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -127,7 +127,6 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, fml::TaskQueueId ui_task_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId(); - task_runners_.GetUITaskRunner()->PostTask( [ui_task_queue_id, callback, flow_identifier, frame_start_time, frame_target_time, pause_secondary_tasks]() { diff --git a/shell/platform/android/android_context_gl_impeller.cc b/shell/platform/android/android_context_gl_impeller.cc index 43979768117c6..31ad0a5551391 100644 --- a/shell/platform/android/android_context_gl_impeller.cc +++ b/shell/platform/android/android_context_gl_impeller.cc @@ -11,6 +11,8 @@ #include "flutter/impeller/toolkit/egl/surface.h" #include "impeller/entity/gles/entity_shaders_gles.h" #include "impeller/entity/gles/framebuffer_blend_shaders_gles.h" +#include "impeller/entity/gles3/entity_shaders_gles.h" +#include "impeller/entity/gles3/framebuffer_blend_shaders_gles.h" namespace flutter { @@ -55,8 +57,10 @@ static std::shared_ptr CreateImpellerContext( FML_LOG(ERROR) << "Could not create OpenGL proc table."; return nullptr; } + bool is_gles3 = proc_table->GetDescription()->GetGlVersion().IsAtLeast( + impeller::Version{3, 0, 0}); - std::vector> shader_mappings = { + std::vector> gles2_shader_mappings = { std::make_shared( impeller_entity_shaders_gles_data, impeller_entity_shaders_gles_length), @@ -65,8 +69,19 @@ static std::shared_ptr CreateImpellerContext( impeller_framebuffer_blend_shaders_gles_length), }; + std::vector> gles3_shader_mappings = { + std::make_shared( + impeller_entity_shaders_gles3_data, + impeller_entity_shaders_gles3_length), + std::make_shared( + impeller_framebuffer_blend_shaders_gles3_data, + impeller_framebuffer_blend_shaders_gles3_length), + }; + auto context = impeller::ContextGLES::Create( - std::move(proc_table), shader_mappings, enable_gpu_tracing); + std::move(proc_table), + is_gles3 ? gles3_shader_mappings : gles2_shader_mappings, + enable_gpu_tracing); if (!context) { FML_LOG(ERROR) << "Could not create OpenGLES Impeller Context."; return nullptr; diff --git a/shell/platform/android/android_context_gl_unittests.cc b/shell/platform/android/android_context_gl_unittests.cc index 5173f59d673db..33416e0182264 100644 --- a/shell/platform/android/android_context_gl_unittests.cc +++ b/shell/platform/android/android_context_gl_unittests.cc @@ -13,6 +13,7 @@ #include "fml/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "impeller/core/runtime_types.h" #include "shell/platform/android/context/android_context.h" namespace flutter { @@ -84,6 +85,10 @@ class TestImpellerContext : public impeller::Context { void Shutdown() override { did_shutdown = true; } + impeller::RuntimeStageBackend GetRuntimeStageBackend() const override { + return impeller::RuntimeStageBackend::kVulkan; + } + bool did_shutdown = false; }; diff --git a/shell/platform/android/build.gradle b/shell/platform/android/build.gradle index 9f8b409965b3f..11dd5f89c4474 100644 --- a/shell/platform/android/build.gradle +++ b/shell/platform/android/build.gradle @@ -8,7 +8,7 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:7.4.2" + classpath "com.android.tools.build:gradle:8.7.2" } } @@ -20,6 +20,7 @@ repositories { apply plugin: "com.android.library" android { + namespace "io.flutter.embedding" compileSdk 35 defaultConfig { @@ -52,7 +53,7 @@ android { implementation "androidx.test:core:1.4.0" implementation "com.google.android.play:core:1.8.0" implementation "com.ibm.icu:icu4j:69.1" - implementation "org.robolectric:robolectric:4.12.1" + implementation "org.robolectric:robolectric:4.14.1" implementation "junit:junit:4.13.2" implementation "androidx.test.ext:junit:1.1.4-alpha07" diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index f5794335b74f4..b46a8e702954f 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -212,7 +212,7 @@ public class FlutterActivity extends Activity implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner { private static final String TAG = "FlutterActivity"; - private boolean hasRegisteredBackCallback = false; + @VisibleForTesting boolean hasRegisteredBackCallback = false; /** * The ID of the {@code FlutterView} created by this activity. @@ -634,6 +634,13 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + boolean frameworkHandlesBack = + savedInstanceState.getBoolean( + FlutterActivityAndFragmentDelegate.ON_BACK_CALLBACK_ENABLED_KEY); + setFrameworkHandlesBack(frameworkHandlesBack); + } + delegate = new FlutterActivityAndFragmentDelegate(this); delegate.onAttach(this); delegate.onRestoreInstanceState(savedInstanceState); @@ -1477,6 +1484,11 @@ public boolean attachToEngineAutomatically() { return true; } + @Override + public boolean getBackCallbackState() { + return hasRegisteredBackCallback; + } + @Override public boolean popSystemNavigator() { // Hook for subclass. No-op if returns false. diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index c576eacda8c0c..630d3dff4f4c9 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -76,6 +76,7 @@ private static final String TAG = "FlutterActivityAndFragmentDelegate"; private static final String FRAMEWORK_RESTORATION_BUNDLE_KEY = "framework"; private static final String PLUGINS_RESTORATION_BUNDLE_KEY = "plugins"; + static final String ON_BACK_CALLBACK_ENABLED_KEY = "enableOnBackInvokedCallbackState"; private static final int FLUTTER_SPLASH_VIEW_FALLBACK_ID = 486947586; /** Factory to obtain a FlutterActivityAndFragmentDelegate instance. */ @@ -691,6 +692,12 @@ void onSaveInstanceState(@Nullable Bundle bundle) { flutterEngine.getActivityControlSurface().onSaveInstanceState(plugins); bundle.putBundle(PLUGINS_RESTORATION_BUNDLE_KEY, plugins); } + + // If using a cached engine, we need to save whether the framework or the system should handle + // backs. + if (host.getCachedEngineId() != null && !host.shouldDestroyEngineWithHost()) { + bundle.putBoolean(ON_BACK_CALLBACK_ENABLED_KEY, host.getBackCallbackState()); + } } @Override @@ -1297,5 +1304,7 @@ PlatformPlugin providePlatformPlugin( *

Defaults to {@code true}. */ boolean attachToEngineAutomatically(); + + boolean getBackCallbackState(); } } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index e26d13e80f74a..fd2021b590ec4 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -1009,7 +1009,8 @@ public FlutterActivityAndFragmentDelegate createDelegate( return new FlutterActivityAndFragmentDelegate(host); } - private final OnBackPressedCallback onBackPressedCallback = + @VisibleForTesting + final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { @@ -1071,6 +1072,12 @@ public void onAttach(@NonNull Context context) { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + boolean frameworkHandlesBack = + savedInstanceState.getBoolean( + FlutterActivityAndFragmentDelegate.ON_BACK_CALLBACK_ENABLED_KEY); + onBackPressedCallback.setEnabled(frameworkHandlesBack); + } delegate.onRestoreInstanceState(savedInstanceState); } @@ -1655,6 +1662,11 @@ public boolean attachToEngineAutomatically() { return true; } + @Override + public boolean getBackCallbackState() { + return onBackPressedCallback.isEnabled(); + } + /** * {@inheritDoc} * diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 0f28573023593..51d2070929f3d 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -2120,7 +2120,8 @@ public enum Action { MOVE_CURSOR_FORWARD_BY_WORD(1 << 19), MOVE_CURSOR_BACKWARD_BY_WORD(1 << 20), SET_TEXT(1 << 21), - FOCUS(1 << 22); + FOCUS(1 << 22), + SCROLL_TO_OFFSET(1 << 23); public final int value; diff --git a/shell/platform/android/surface_texture_external_texture.cc b/shell/platform/android/surface_texture_external_texture.cc index 383823585ce51..ed019b9101a16 100644 --- a/shell/platform/android/surface_texture_external_texture.cc +++ b/shell/platform/android/surface_texture_external_texture.cc @@ -52,7 +52,10 @@ void SurfaceTextureExternalTexture::Paint(PaintContext& context, if (should_process_frame) { ProcessFrame(context, bounds); } - FML_CHECK(state_ == AttachmentState::kAttached); + // If process frame failed, this may not be in attached state. + if (state_ != AttachmentState::kAttached) { + return; + } if (!dl_image_) { FML_LOG(WARNING) diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java index 8833b7a96dbe3..d3686a6dbcf11 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java @@ -5,6 +5,7 @@ package io.flutter.embedding.android; import static io.flutter.Build.API_LEVELS; +import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_ID; import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.HANDLE_DEEPLINKING_META_DATA_KEY; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -34,6 +35,7 @@ import androidx.annotation.RequiresApi; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; +import androidx.test.core.app.ActivityScenario; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import io.flutter.FlutterInjector; @@ -94,6 +96,48 @@ public void flutterViewHasId() { assertTrue(activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID) instanceof FlutterView); } + @Test + @Config(minSdk = API_LEVELS.API_34) + @TargetApi(API_LEVELS.API_34) + public void whenUsingCachedEngine_predictiveBackStateIsSaved() { + FlutterLoader mockFlutterLoader = mock(FlutterLoader.class); + FlutterJNI mockFlutterJni = mock(FlutterJNI.class); + when(mockFlutterJni.isAttached()).thenReturn(true); + FlutterEngine cachedEngine = new FlutterEngine(ctx, mockFlutterLoader, mockFlutterJni); + FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); + + ActivityScenario flutterActivityScenario = + ActivityScenario.launch(FlutterActivity.class); + + // Set to framework handling and then recreate the activity and check the state is preserved. + flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); + flutterActivityScenario.onActivity( + activity -> activity.getIntent().putExtra(EXTRA_CACHED_ENGINE_ID, "my_cached_engine")); + + flutterActivityScenario.recreate(); + flutterActivityScenario.onActivity(activity -> assertTrue(activity.hasRegisteredBackCallback)); + + // Clean up. + flutterActivityScenario.close(); + } + + @Test + @Config(minSdk = API_LEVELS.API_34) + @TargetApi(API_LEVELS.API_34) + public void whenNotUsingCachedEngine_predictiveBackStateIsNotSaved() { + ActivityScenario flutterActivityScenario = + ActivityScenario.launch(FlutterActivity.class); + + // Set to framework handling and then recreate the activity and check the state is preserved. + flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); + + flutterActivityScenario.recreate(); + flutterActivityScenario.onActivity(activity -> assertFalse(activity.hasRegisteredBackCallback)); + + // Clean up. + flutterActivityScenario.close(); + } + // TODO(garyq): Robolectric does not yet support android api 33 yet. Switch to a robolectric // test that directly exercises the OnBackInvoked APIs when API 33 is supported. @Test diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java index 8e8c77619f887..901ac61b2a002 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java @@ -401,6 +401,11 @@ public boolean attachToEngineAutomatically() { return true; } + @Override + public boolean getBackCallbackState() { + return false; + } + @Override public void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView) {} diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java index 97701775adc8e..73274cbce9766 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java @@ -5,6 +5,8 @@ package io.flutter.embedding.android; import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.HANDLE_DEEPLINKING_META_DATA_KEY; +import static io.flutter.embedding.android.FlutterFragment.ARG_CACHED_ENGINE_ID; +import static io.flutter.embedding.android.FlutterFragment.ARG_DESTROY_ENGINE_WITH_FRAGMENT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -13,6 +15,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -25,9 +28,11 @@ import androidx.test.core.app.ActivityScenario; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import io.flutter.Build; import io.flutter.FlutterInjector; import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode; import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.embedding.engine.FlutterEngineCache; import io.flutter.embedding.engine.FlutterJNI; import io.flutter.embedding.engine.loader.FlutterLoader; import io.flutter.plugins.GeneratedPluginRegistrant; @@ -254,6 +259,63 @@ public void itHandlesNewFragmentRecreationDuringRestoreWhenActivityIsRecreated() assertEquals(0, activity.numberOfEnginesCreated); } + @Test + @Config(minSdk = Build.API_LEVELS.API_34) + @TargetApi(Build.API_LEVELS.API_34) + public void whenUsingCachedEngine_predictiveBackStateIsSaved() { + FlutterLoader mockFlutterLoader = mock(FlutterLoader.class); + FlutterJNI mockFlutterJni = mock(FlutterJNI.class); + when(mockFlutterJni.isAttached()).thenReturn(true); + FlutterEngine cachedEngine = new FlutterEngine(ctx, mockFlutterLoader, mockFlutterJni); + FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); + + ActivityScenario flutterFragmentActivityActivityScenario = + ActivityScenario.launch(FlutterFragmentActivity.class); + + // Set to framework handling and then recreate the activity and check the state is preserved. + flutterFragmentActivityActivityScenario.onActivity( + activity -> { + FlutterFragment flutterFragment = activity.retrieveExistingFlutterFragmentIfPossible(); + flutterFragment.setFrameworkHandlesBack(true); + Bundle bundle = flutterFragment.getArguments(); + bundle.putString(ARG_CACHED_ENGINE_ID, "my_cached_engine"); + bundle.putBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, false); + FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); + flutterFragment.setArguments(bundle); + }); + + flutterFragmentActivityActivityScenario.recreate(); + + flutterFragmentActivityActivityScenario.onActivity( + activity -> { + assertTrue( + activity + .retrieveExistingFlutterFragmentIfPossible() + .onBackPressedCallback + .isEnabled()); + }); + + // Clean up. + flutterFragmentActivityActivityScenario.close(); + } + + @Test + @Config(minSdk = Build.API_LEVELS.API_34) + @TargetApi(Build.API_LEVELS.API_34) + public void whenNotUsingCachedEngine_predictiveBackStateIsNotSaved() { + ActivityScenario flutterActivityScenario = + ActivityScenario.launch(FlutterActivity.class); + + // Set to framework handling and then recreate the activity and check the state is preserved. + flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); + + flutterActivityScenario.recreate(); + flutterActivityScenario.onActivity(activity -> assertFalse(activity.hasRegisteredBackCallback)); + + // Clean up. + flutterActivityScenario.close(); + } + static class FlutterFragmentActivityWithProvidedEngine extends FlutterFragmentActivity { int numberOfEnginesCreated = 0; diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/KeyEventChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/KeyEventChannelTest.java index 0b1ec96a0789f..815adfc11ebe1 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/KeyEventChannelTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/KeyEventChannelTest.java @@ -9,14 +9,10 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.annotation.TargetApi; -import android.util.SparseArray; -import android.view.InputDevice; import android.view.KeyEvent; import androidx.test.ext.junit.runners.AndroidJUnit4; import io.flutter.plugin.common.BinaryMessenger; @@ -25,7 +21,6 @@ import java.nio.ByteBuffer; import org.json.JSONException; import org.json.JSONObject; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,14 +28,10 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.annotation.Resetter; -import org.robolectric.shadow.api.Shadow; @Config(manifest = Config.NONE) @RunWith(AndroidJUnit4.class) -@TargetApi(API_LEVELS.API_24) +@TargetApi(API_LEVELS.API_35) public class KeyEventChannelTest { KeyEvent keyEvent; @@ -66,20 +57,8 @@ public void setUp() { keyEventChannel = new KeyEventChannel(fakeMessenger); } - @After - public void tearDown() { - ShadowInputDevice.reset(); - } - @Test - @Config(shadows = {ShadowInputDevice.class}) public void keyDownEventIsSentToFramework() throws JSONException { - final InputDevice device = mock(InputDevice.class); - when(device.isVirtual()).thenReturn(false); - when(device.getName()).thenReturn("keyboard"); - ShadowInputDevice.sDeviceIds = new int[] {0}; - ShadowInputDevice.addDevice(0, device); - KeyEventChannel.FlutterKeyEvent flutterKeyEvent = new KeyEventChannel.FlutterKeyEvent(keyEvent, null); keyEventChannel.sendFlutterKeyEvent( @@ -106,14 +85,7 @@ public void keyDownEventIsSentToFramework() throws JSONException { } @Test - @Config(shadows = {ShadowInputDevice.class}) public void keyUpEventIsSentToFramework() throws JSONException { - final InputDevice device = mock(InputDevice.class); - when(device.isVirtual()).thenReturn(false); - when(device.getName()).thenReturn("keyboard"); - ShadowInputDevice.sDeviceIds = new int[] {0}; - ShadowInputDevice.addDevice(0, device); - keyEvent = new FakeKeyEvent(KeyEvent.ACTION_UP, 65); KeyEventChannel.FlutterKeyEvent flutterKeyEvent = new KeyEventChannel.FlutterKeyEvent(keyEvent, null); @@ -139,48 +111,4 @@ public void keyUpEventIsSentToFramework() throws JSONException { sendReply(true, replyArgumentCaptor.getValue()); assertTrue(handled[0]); } - - @Implements(InputDevice.class) - public static class ShadowInputDevice extends org.robolectric.shadows.ShadowInputDevice { - public static int[] sDeviceIds; - private static SparseArray sDeviceMap = new SparseArray<>(); - - private int mDeviceId; - - @Implementation - protected static int[] getDeviceIds() { - return sDeviceIds; - } - - @Implementation - protected static InputDevice getDevice(int id) { - return sDeviceMap.get(id); - } - - public static void addDevice(int id, InputDevice device) { - sDeviceMap.append(id, device); - } - - @Resetter - public static void reset() { - sDeviceIds = null; - sDeviceMap.clear(); - } - - @Implementation - protected int getId() { - return mDeviceId; - } - - public static InputDevice makeInputDevicebyId(int id) { - final InputDevice inputDevice = Shadow.newInstanceOf(InputDevice.class); - final ShadowInputDevice shadowInputDevice = Shadow.extract(inputDevice); - shadowInputDevice.setId(id); - return inputDevice; - } - - public void setId(int id) { - mDeviceId = id; - } - } } diff --git a/shell/platform/android/test_runner/build.gradle b/shell/platform/android/test_runner/build.gradle index 458cc13d6b5fe..5e5243f14a2d0 100644 --- a/shell/platform/android/test_runner/build.gradle +++ b/shell/platform/android/test_runner/build.gradle @@ -4,7 +4,7 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:8.5.0" + classpath "com.android.tools.build:gradle:8.7.2" } } @@ -71,7 +71,7 @@ android { testImplementation "androidx.test:core:1.4.0" testImplementation "com.google.android.play:core:1.8.0" testImplementation "com.ibm.icu:icu4j:69.1" - testImplementation "org.robolectric:robolectric:4.12.1" + testImplementation "org.robolectric:robolectric:4.14.1" testImplementation "junit:junit:4.13.2" testImplementation "androidx.test.ext:junit:1.1.4-alpha07" diff --git a/shell/platform/android/test_runner/src/main/resources/robolectric.properties b/shell/platform/android/test_runner/src/main/resources/robolectric.properties index ebf6f5b5a478d..7e47f6fb21ee6 100644 --- a/shell/platform/android/test_runner/src/main/resources/robolectric.properties +++ b/shell/platform/android/test_runner/src/main/resources/robolectric.properties @@ -1,2 +1,2 @@ -sdk=33 +sdk=35 shadows=io.flutter.CustomShadowContextImpl diff --git a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm index af73983665ff1..3e41eedf91e2d 100644 --- a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm +++ b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm @@ -25,14 +25,8 @@ std::make_shared(impeller_framebuffer_blend_shaders_data, impeller_framebuffer_blend_shaders_length), }; - auto context = impeller::ContextMTL::Create(shader_mappings, is_gpu_disabled_sync_switch, - "Impeller Library"); - if (!context) { - FML_LOG(ERROR) << "Could not create Metal Impeller Context."; - return nullptr; - } - - return context; + return impeller::ContextMTL::Create(shader_mappings, is_gpu_disabled_sync_switch, + "Impeller Library"); } @implementation FlutterDarwinContextMetalImpeller @@ -41,11 +35,9 @@ - (instancetype)init:(const std::shared_ptr&)is_gpu_disab self = [super init]; if (self != nil) { _context = CreateImpellerContext(is_gpu_disabled_sync_switch); + FML_CHECK(_context) << "Could not create Metal Impeller Context."; id device = _context->GetMTLDevice(); - if (!device) { - FML_DLOG(ERROR) << "Could not acquire Metal device."; - return nil; - } + FML_CHECK(device) << "Could not acquire Metal device."; CVMetalTextureCacheRef textureCache; CVReturn cvReturn = CVMetalTextureCacheCreate(kCFAllocatorDefault, // allocator @@ -55,10 +47,7 @@ - (instancetype)init:(const std::shared_ptr&)is_gpu_disab &textureCache // [out] cache ); - if (cvReturn != kCVReturnSuccess) { - FML_DLOG(ERROR) << "Could not create Metal texture cache."; - return nil; - } + FML_CHECK(cvReturn == kCVReturnSuccess) << "Could not acquire Metal device."; _textureCache.Reset(textureCache); } return self; diff --git a/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.mm b/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.mm index 16642cd1544cb..390328f1ed435 100644 --- a/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.mm +++ b/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.mm @@ -84,8 +84,6 @@ - (instancetype)initWithMTLDevice:(id)device } - (sk_sp)createGrContext { - const auto contextOptions = - flutter::MakeDefaultContextOptions(flutter::ContextType::kRender, GrBackendApi::kMetal); id device = _device; id commandQueue = _commandQueue; return [FlutterDarwinContextMetalSkia createGrContext:device commandQueue:commandQueue]; diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 85616de70f156..6020365844afb 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -79,8 +79,10 @@ source_set("flutter_framework_source") { "framework/Source/FlutterOverlayView.mm", "framework/Source/FlutterPlatformPlugin.h", "framework/Source/FlutterPlatformPlugin.mm", + "framework/Source/FlutterPlatformViews.mm", + "framework/Source/FlutterPlatformViewsController.h", + "framework/Source/FlutterPlatformViewsController.mm", "framework/Source/FlutterPlatformViews_Internal.h", - "framework/Source/FlutterPlatformViews_Internal.mm", "framework/Source/FlutterPluginAppLifeCycleDelegate.mm", "framework/Source/FlutterRestorationPlugin.h", "framework/Source/FlutterRestorationPlugin.mm", @@ -120,8 +122,6 @@ source_set("flutter_framework_source") { "framework/Source/overlay_layer_pool.mm", "framework/Source/platform_message_response_darwin.h", "framework/Source/platform_message_response_darwin.mm", - "framework/Source/platform_views_controller.h", - "framework/Source/platform_views_controller.mm", "framework/Source/profiler_metrics_ios.h", "framework/Source/profiler_metrics_ios.mm", "framework/Source/vsync_waiter_ios.h", @@ -165,6 +165,7 @@ source_set("flutter_framework_source") { "CoreVideo.framework", "IOSurface.framework", "QuartzCore.framework", + "WebKit.framework", "UIKit.framework", ] if (flutter_runtime_mode == "profile" || flutter_runtime_mode == "debug") { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 85f1ba5519914..eff08e6cc53e5 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -105,6 +105,8 @@ @interface FlutterEngine () _threadHost; std::unique_ptr _shell; - std::shared_ptr _platformViewsController; flutter::IOSRenderingAPI _renderingApi; std::shared_ptr _profiler; @@ -211,7 +212,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix _pluginPublications = [[NSMutableDictionary alloc] init]; _registrars = [[NSMutableDictionary alloc] init]; - [self recreatePlatformViewController]; + [self recreatePlatformViewsController]; _binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self]; _textureRegistry = [[FlutterTextureRegistryRelay alloc] initWithParent:self]; _connections.reset(new flutter::ConnectionCollection()); @@ -262,9 +263,9 @@ - (void)setUpApplicationLifecycleNotifications:(NSNotificationCenter*)center { object:nil]; } -- (void)recreatePlatformViewController { +- (void)recreatePlatformViewsController { _renderingApi = flutter::GetRenderingAPIForProcess(FlutterView.forceSoftwareRendering); - _platformViewsController.reset(new flutter::PlatformViewsController()); + _platformViewsController = [[FlutterPlatformViewsController alloc] init]; } - (flutter::IOSRenderingAPI)platformViewsRenderingAPI { @@ -452,11 +453,7 @@ - (void)destroyContext { _shell.reset(); _profiler.reset(); _threadHost.reset(); - _platformViewsController.reset(); -} - -- (std::shared_ptr&)platformViewsController { - return _platformViewsController; + _platformViewsController = nil; } - (NSURL*)observatoryUrl { @@ -635,7 +632,7 @@ - (void)maybeSetupPlatformViewChannels { [self.platformViewsChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { if (weakSelf) { - weakSelf.platformViewsController->OnMethodCall(call, result); + [weakSelf.platformViewsController onMethodCall:call result:result]; } }]; @@ -777,11 +774,11 @@ - (BOOL)createShell:(NSString*)entrypoint if (!strongSelf) { return std::unique_ptr(); } - [strongSelf recreatePlatformViewController]; - strongSelf->_platformViewsController->SetTaskRunner( - shell.GetTaskRunners().GetPlatformTaskRunner()); + [strongSelf recreatePlatformViewsController]; + strongSelf.platformViewsController.taskRunner = + shell.GetTaskRunners().GetPlatformTaskRunner(); return std::make_unique( - shell, strongSelf->_renderingApi, strongSelf->_platformViewsController, + shell, strongSelf->_renderingApi, strongSelf.platformViewsController, shell.GetTaskRunners(), shell.GetConcurrentWorkerTaskRunner(), shell.GetIsGpuDisabledSyncSwitch()); }; @@ -1103,7 +1100,7 @@ - (void)flutterTextInputView:(FlutterTextInputView*)textInputView // Have to check in the next run loop, because iOS requests the previous first responder to // resign before requesting the next view to become first responder. dispatch_async(dispatch_get_main_queue(), ^(void) { - long platform_view_id = self.platformViewsController->FindFirstResponderPlatformViewId(); + long platform_view_id = [self.platformViewsController firstResponderPlatformViewId]; if (platform_view_id == -1) { return; } @@ -1400,11 +1397,10 @@ - (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint // create call is synchronous. flutter::Shell::CreateCallback on_create_platform_view = [result, context](flutter::Shell& shell) { - [result recreatePlatformViewController]; - result->_platformViewsController->SetTaskRunner( - shell.GetTaskRunners().GetPlatformTaskRunner()); + [result recreatePlatformViewsController]; + result.platformViewsController.taskRunner = shell.GetTaskRunners().GetPlatformTaskRunner(); return std::make_unique( - shell, context, result->_platformViewsController, shell.GetTaskRunners()); + shell, context, result.platformViewsController, shell.GetTaskRunners()); }; flutter::Shell::CreateCallback on_create_rasterizer = @@ -1499,8 +1495,9 @@ - (void)registerViewFactory:(NSObject*)factory withId:(NSString*)factoryId gestureRecognizersBlockingPolicy: (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy { - [_flutterEngine platformViewsController]->RegisterViewFactory(factory, factoryId, - gestureRecognizersBlockingPolicy); + [_flutterEngine.platformViewsController registerViewFactory:factory + withId:factoryId + gestureRecognizersBlockingPolicy:gestureRecognizersBlockingPolicy]; } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h index 6f954adbcbce9..bb3beca9dbbd2 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h @@ -46,7 +46,6 @@ NS_ASSUME_NONNULL_BEGIN base64Encode:(bool)base64Encode; - (FlutterPlatformPlugin*)platformPlugin; -- (std::shared_ptr&)platformViewsController; - (FlutterTextInputPlugin*)textInputPlugin; - (FlutterRestorationPlugin*)restorationPlugin; - (void)launchEngine:(nullable NSString*)entrypoint @@ -81,6 +80,7 @@ NS_ASSUME_NONNULL_BEGIN userData:(nullable void*)userData; @property(nonatomic, readonly) FlutterDartProject* project; + @end NS_ASSUME_NONNULL_END diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm similarity index 95% rename from shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm rename to shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index ce381243653ba..a036668fce3ce 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -4,6 +4,8 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" +#import + #include "flutter/display_list/effects/dl_image_filter.h" #include "flutter/fml/platform/darwin/cf_utils.h" #import "flutter/shell/platform/darwin/ios/ios_surface.h" @@ -518,8 +520,7 @@ @interface FlutterTouchInterceptingView () @implementation FlutterTouchInterceptingView - (instancetype)initWithEmbeddedView:(UIView*)embeddedView - platformViewsController: - (fml::WeakPtr)platformViewsController + platformViewsController:(FlutterPlatformViewsController*)platformViewsController gestureRecognizersBlockingPolicy: (FlutterPlatformViewGestureRecognizersBlockingPolicy)blockingPolicy { self = [super initWithFrame:embeddedView.frame]; @@ -570,6 +571,22 @@ - (void)blockGesture { case FlutterPlatformViewGestureRecognizersBlockingPolicyEager: // We block all other gesture recognizers immediately in this policy. self.delayingRecognizer.state = UIGestureRecognizerStateEnded; + + // On iOS 18.2, WKWebView's internal recognizer likely caches the old state of its blocking + // recognizers (i.e. delaying recognizer), resulting in non-tappable links. See + // https://github.com/flutter/flutter/issues/158961. Removing and adding back the delaying + // recognizer solves the problem, possibly because UIKit notifies all the recognizers related + // to (blocking or blocked by) this recognizer. It is not possible to inject this workaround + // from the web view plugin level. Right now we only observe this issue for + // FlutterPlatformViewGestureRecognizersBlockingPolicyEager, but we should try it if a similar + // issue arises for the other policy. + if (@available(iOS 18.2, *)) { + if ([self.embeddedView isKindOfClass:[WKWebView class]]) { + [self removeGestureRecognizer:self.delayingRecognizer]; + [self addGestureRecognizer:self.delayingRecognizer]; + } + } + break; case FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded: if (self.delayingRecognizer.touchedEndedWithoutBlocking) { @@ -667,7 +684,7 @@ @implementation ForwardingGestureRecognizer { // outlives the FlutterViewController. And ForwardingGestureRecognizer is owned by a subview of // FlutterView, so the ForwardingGestureRecognizer never out lives FlutterViewController. // Therefore, `_platformViewsController` should never be nullptr. - fml::WeakPtr _platformViewsController; + __weak FlutterPlatformViewsController* _platformViewsController; // Counting the pointers that has started in one touch sequence. NSInteger _currentTouchPointersCount; // We can't dispatch events to the framework without this back pointer. @@ -678,13 +695,12 @@ @implementation ForwardingGestureRecognizer { } - (instancetype)initWithTarget:(id)target - platformViewsController: - (fml::WeakPtr)platformViewsController { + platformViewsController:(FlutterPlatformViewsController*)platformViewsController { self = [super initWithTarget:target action:nil]; if (self) { self.delegate = self; - FML_DCHECK(platformViewsController.get() != nullptr); - _platformViewsController = std::move(platformViewsController); + FML_DCHECK(platformViewsController); + _platformViewsController = platformViewsController; _currentTouchPointersCount = 0; } return self; @@ -692,7 +708,7 @@ - (instancetype)initWithTarget:(id)target - (ForwardingGestureRecognizer*)recreateRecognizerWithTarget:(id)target { return [[ForwardingGestureRecognizer alloc] initWithTarget:target - platformViewsController:std::move(_platformViewsController)]; + platformViewsController:_platformViewsController]; } - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { @@ -701,7 +717,7 @@ - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { // At the start of each gesture sequence, we reset the `_flutterViewController`, // so that all the touch events in the same sequence are forwarded to the same // `_flutterViewController`. - _flutterViewController = _platformViewsController->GetFlutterViewController(); + _flutterViewController = _platformViewsController.flutterViewController; } [_flutterViewController touchesBegan:touches withEvent:event]; _currentTouchPointersCount += touches.count; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h new file mode 100644 index 0000000000000..5b55ce6d72f28 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h @@ -0,0 +1,150 @@ +// 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_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWSCONTROLLER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWSCONTROLLER_H_ + +#include +#include +#include +#include + +#include "flutter/flow/surface.h" +#include "flutter/fml/task_runner.h" +#include "flutter/fml/trace_event.h" +#include "impeller/base/thread_safety.h" +#include "third_party/skia/include/core/SkRect.h" + +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h" +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h" +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewResponder.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_pool.h" +#import "flutter/shell/platform/darwin/ios/ios_context.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FlutterTouchInterceptingView; +@class FlutterClippingMaskViewPool; + +@interface FlutterPlatformViewsController : NSObject + +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +/// The task runner used to post rendering tasks to the platform thread. +@property(nonatomic, assign) const fml::RefPtr& taskRunner; + +/// The flutter view. +@property(nonatomic, weak) UIView* _Nullable flutterView; + +/// @brief The flutter view controller. +@property(nonatomic, weak) UIViewController* _Nullable flutterViewController; + +/// @brief set the factory used to construct embedded UI Views. +- (void)registerViewFactory:(NSObject*)factory + withId:(NSString*)factoryId + gestureRecognizersBlockingPolicy: + (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizerBlockingPolicy; + +/// @brief Mark the beginning of a frame and record the size of the onscreen. +- (void)beginFrameWithSize:(SkISize)frameSize; + +/// @brief Cancel the current frame, indicating that no platform views are composited. +/// +/// Additionally, reverts the composition order to its original state at the beginning of the +/// frame. +- (void)cancelFrame; + +/// @brief Record a platform view in the layer tree to be rendered, along with the positioning and +/// mutator parameters. +/// +/// Called from the raster thread. +- (void)prerollCompositeEmbeddedView:(int64_t)viewId + withParams:(std::unique_ptr)params; + +/// @brief Returns the`FlutterTouchInterceptingView` with the provided view_id. +/// +/// Returns nil if there is no platform view with the provided id. Called +/// from the platform thread. +- (FlutterTouchInterceptingView*)flutterTouchInterceptingViewForId:(int64_t)viewId; + +/// @brief Determine if thread merging is required after prerolling platform views. +/// +/// Called from the raster thread. +- (flutter::PostPrerollResult)postPrerollActionWithThreadMerger: + (const fml::RefPtr&)rasterThreadMerger + impellerEnabled:(BOOL)impellerEnabled; + +/// @brief Mark the end of a compositor frame. +/// +/// May determine changes are required to the thread merging state. +/// Called from the raster thread. +- (void)endFrameWithResubmit:(BOOL)shouldResubmitFrame + threadMerger:(const fml::RefPtr&)rasterThreadMerger + impellerEnabled:(BOOL)impellerEnabled; + +/// @brief Returns the Canvas for the overlay slice for the given platform view. +/// +/// Called from the raster thread. +- (flutter::DlCanvas*)compositeEmbeddedViewWithId:(int64_t)viewId; + +/// @brief Discards all platform views instances and auxiliary resources. +/// +/// Called from the raster thread. +- (void)reset; + +/// @brief Encode rendering for the Flutter overlay views and queue up perform platform view +/// mutations. +/// +/// Called from the raster thread. +- (BOOL)submitFrame:(std::unique_ptr)frame + withIosContext:(const std::shared_ptr&)iosContext + grContext:(GrDirectContext* _Nullable)grContext; + +/// @brief Handler for platform view message channels. +- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result; + +/// @brief Returns the platform view id if the platform view (or any of its descendant view) is +/// the first responder. +/// +/// Returns -1 if no such platform view is found. +- (long)firstResponderPlatformViewId; + +/// @brief Pushes backdrop filter mutation to the mutator stack of each visited platform view. +- (void)pushFilterToVisitedPlatformViews:(const std::shared_ptr&)filter + withRect:(const SkRect&)filterRect; + +/// @brief Pushes the view id of a visted platform view to the list of visied platform views. +- (void)pushVisitedPlatformViewId:(int64_t)viewId; + +@end + +@interface FlutterPlatformViewsController (Testing) + +- (size_t)embeddedViewCount; + +// Returns the `FlutterPlatformView`'s `view` object associated with the view_id. +// +// If the `PlatformViewsController` does not contain any `FlutterPlatformView` object or +// a `FlutterPlatformView` object associated with the view_id cannot be found, the method +// returns nil. +- (UIView* _Nullable)platformViewForId:(int64_t)viewId; + +// Composite the PlatformView with `viewId`. +// +// Every frame, during the paint traversal of the layer tree, this method is called for all +// the PlatformViews in `_viewsToRecomposite`. +// +// Note that `_viewsToRecomposite` does not represent all the views in the view hierarchy, +// if a PlatformView does not change its composition parameter from last frame, it is not +// included in the `views_to_recomposite_`. +- (void)compositeView:(int64_t)viewId withParams:(const flutter::EmbeddedViewParams&)params; + +- (const flutter::EmbeddedViewParams&)compositionParamsForView:(int64_t)viewId; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWSCONTROLLER_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm new file mode 100644 index 0000000000000..7a452ba74443f --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm @@ -0,0 +1,1075 @@ +// 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. + +#import "shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h" + +#include "flutter/display_list/effects/image_filters/dl_blur_image_filter.h" +#include "flutter/flow/surface_frame.h" +#include "flutter/flow/view_slicer.h" +#include "flutter/fml/make_copyable.h" +#include "flutter/fml/synchronization/count_down_latch.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_pool.h" +#import "flutter/shell/platform/darwin/ios/ios_surface.h" + +// The number of frames the rasterizer task runner will continue +// to run on the platform thread after no platform view is rendered. +// +// Note: this is an arbitrary number. +static constexpr int kDefaultMergedLeaseDuration = 10; + +static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity = 5; + +struct LayerData { + SkRect rect; + int64_t view_id; + int64_t overlay_id; + std::shared_ptr layer; +}; +using LayersMap = std::unordered_map; + +/// Each of the following structs stores part of the platform view hierarchy according to its +/// ID. +/// +/// This data must only be accessed on the platform thread. +struct PlatformViewData { + NSObject* view; + FlutterTouchInterceptingView* touch_interceptor; + UIView* root_view; +}; + +// Converts a SkMatrix to CATransform3D. +// +// Certain fields are ignored in CATransform3D since SkMatrix is 3x3 and CATransform3D is 4x4. +static CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix) { + // Skia only supports 2D transform so we don't map z. + CATransform3D transform = CATransform3DIdentity; + transform.m11 = matrix.getScaleX(); + transform.m21 = matrix.getSkewX(); + transform.m41 = matrix.getTranslateX(); + transform.m14 = matrix.getPerspX(); + + transform.m12 = matrix.getSkewY(); + transform.m22 = matrix.getScaleY(); + transform.m42 = matrix.getTranslateY(); + transform.m24 = matrix.getPerspY(); + return transform; +} + +// Reset the anchor of `layer` to match the transform operation from flow. +// +// The position of the `layer` should be unchanged after resetting the anchor. +static void ResetAnchor(CALayer* layer) { + // Flow uses (0, 0) to apply transform matrix so we need to match that in Quartz. + layer.anchorPoint = CGPointZero; + layer.position = CGPointZero; +} + +static CGRect GetCGRectFromSkRect(const SkRect& clipSkRect) { + return CGRectMake(clipSkRect.fLeft, clipSkRect.fTop, clipSkRect.fRight - clipSkRect.fLeft, + clipSkRect.fBottom - clipSkRect.fTop); +} + +// Determines if the `clip_rect` from a clipRect mutator contains the +// `platformview_boundingrect`. +// +// `clip_rect` is in its own coordinate space. The rect needs to be transformed by +// `transform_matrix` to be in the coordinate space where the PlatformView is displayed. +// +// `platformview_boundingrect` is the final bounding rect of the PlatformView in the coordinate +// space where the PlatformView is displayed. +static bool ClipRectContainsPlatformViewBoundingRect(const SkRect& clip_rect, + const SkRect& platformview_boundingrect, + const SkMatrix& transform_matrix) { + SkRect transformed_rect = transform_matrix.mapRect(clip_rect); + return transformed_rect.contains(platformview_boundingrect); +} + +// Determines if the `clipRRect` from a clipRRect mutator contains the +// `platformview_boundingrect`. +// +// `clip_rrect` is in its own coordinate space. The rrect needs to be transformed by +// `transform_matrix` to be in the coordinate space where the PlatformView is displayed. +// +// `platformview_boundingrect` is the final bounding rect of the PlatformView in the coordinate +// space where the PlatformView is displayed. +static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, + const SkRect& platformview_boundingrect, + const SkMatrix& transform_matrix) { + SkVector upper_left = clip_rrect.radii(SkRRect::Corner::kUpperLeft_Corner); + SkVector upper_right = clip_rrect.radii(SkRRect::Corner::kUpperRight_Corner); + SkVector lower_right = clip_rrect.radii(SkRRect::Corner::kLowerRight_Corner); + SkVector lower_left = clip_rrect.radii(SkRRect::Corner::kLowerLeft_Corner); + SkScalar transformed_upper_left_x = transform_matrix.mapRadius(upper_left.x()); + SkScalar transformed_upper_left_y = transform_matrix.mapRadius(upper_left.y()); + SkScalar transformed_upper_right_x = transform_matrix.mapRadius(upper_right.x()); + SkScalar transformed_upper_right_y = transform_matrix.mapRadius(upper_right.y()); + SkScalar transformed_lower_right_x = transform_matrix.mapRadius(lower_right.x()); + SkScalar transformed_lower_right_y = transform_matrix.mapRadius(lower_right.y()); + SkScalar transformed_lower_left_x = transform_matrix.mapRadius(lower_left.x()); + SkScalar transformed_lower_left_y = transform_matrix.mapRadius(lower_left.y()); + SkRect transformed_clip_rect = transform_matrix.mapRect(clip_rrect.rect()); + SkRRect transformed_rrect; + SkVector corners[] = {{transformed_upper_left_x, transformed_upper_left_y}, + {transformed_upper_right_x, transformed_upper_right_y}, + {transformed_lower_right_x, transformed_lower_right_y}, + {transformed_lower_left_x, transformed_lower_left_y}}; + transformed_rrect.setRectRadii(transformed_clip_rect, corners); + return transformed_rrect.contains(platformview_boundingrect); +} + +@interface FlutterPlatformViewsController () + +// The pool of reusable view layers. The pool allows to recycle layer in each frame. +@property(nonatomic, readonly) flutter::OverlayLayerPool* layerPool; + +// The platform view's |EmbedderViewSlice| keyed off the view id, which contains any subsequent +// operation until the next platform view or the end of the last leaf node in the layer tree. +// +// The Slices are deleted by the PlatformViewsController.reset(). +@property(nonatomic, readonly) + std::unordered_map>& slices; + +@property(nonatomic, readonly) FlutterClippingMaskViewPool* maskViewPool; + +@property(nonatomic, readonly) + std::unordered_map*>& factories; + +// The FlutterPlatformViewGestureRecognizersBlockingPolicy for each type of platform view. +@property(nonatomic, readonly) + std::unordered_map& + gestureRecognizersBlockingPolicies; + +/// The size of the current onscreen surface in physical pixels. +@property(nonatomic, assign) SkISize frameSize; + +/// The task runner for posting tasks to the platform thread. +@property(nonatomic, readonly) const fml::RefPtr& platformTaskRunner; + +/// This data must only be accessed on the platform thread. +@property(nonatomic, readonly) std::unordered_map& platformViews; + +/// The composition parameters for each platform view. +/// +/// This state is only modified on the raster thread. +@property(nonatomic, readonly) + std::unordered_map& currentCompositionParams; + +/// Method channel `OnDispose` calls adds the views to be disposed to this set to be disposed on +/// the next frame. +/// +/// This state is modified on both the platform and raster thread. +@property(nonatomic, readonly) std::unordered_set& viewsToDispose; + +/// view IDs in composition order. +/// +/// This state is only modified on the raster thread. +@property(nonatomic, readonly) std::vector& compositionOrder; + +/// platform view IDs visited during layer tree composition. +/// +/// This state is only modified on the raster thread. +@property(nonatomic, readonly) std::vector& visitedPlatformViews; + +/// Only composite platform views in this set. +/// +/// This state is only modified on the raster thread. +@property(nonatomic, readonly) std::unordered_set& viewsToRecomposite; + +/// @brief The composition order from the previous thread. +/// +/// Only accessed from the platform thread. +@property(nonatomic, readonly) std::vector& previousCompositionOrder; + +/// Whether the previous frame had any platform views in active composition order. +/// +/// This state is tracked so that the first frame after removing the last platform view +/// runs through the platform view rendering code path, giving us a chance to remove the +/// platform view from the UIView hierarchy. +/// +/// Only accessed from the raster thread. +@property(nonatomic, assign) BOOL hadPlatformViews; + +/// Whether blurred backdrop filters can be applied. +/// +/// Defaults to YES, but becomes NO if blurred backdrop filters cannot be applied. +@property(nonatomic, assign) BOOL canApplyBlurBackdrop; + +/// Populate any missing overlay layers. +/// +/// This requires posting a task to the platform thread and blocking on its completion. +- (void)createMissingOverlays:(size_t)requiredOverlayLayers + withIosContext:(const std::shared_ptr&)iosContext + grContext:(GrDirectContext*)grContext; + +/// Update the buffers and mutate the platform views in CATransaction on the platform thread. +- (void)performSubmit:(const LayersMap&)platformViewLayers + currentCompositionParams: + (std::unordered_map&)currentCompositionParams + viewsToRecomposite:(const std::unordered_set&)viewsToRecomposite + compositionOrder:(const std::vector&)compositionOrder + unusedLayers: + (const std::vector>&)unusedLayers + surfaceFrames: + (const std::vector>&)surfaceFrames; + +- (void)onCreate:(FlutterMethodCall*)call result:(FlutterResult)result; +- (void)onDispose:(FlutterMethodCall*)call result:(FlutterResult)result; +- (void)onAcceptGesture:(FlutterMethodCall*)call result:(FlutterResult)result; +- (void)onRejectGesture:(FlutterMethodCall*)call result:(FlutterResult)result; + +- (void)clipViewSetMaskView:(UIView*)clipView; + +// Applies the mutators in the mutatorsStack to the UIView chain that was constructed by +// `ReconstructClipViewsChain` +// +// Clips are applied to the `embeddedView`'s super view(|ChildClippingView|) using a +// |FlutterClippingMaskView|. Transforms are applied to `embeddedView` +// +// The `boundingRect` is the final bounding rect of the PlatformView +// (EmbeddedViewParams::finalBoundingRect). If a clip mutator's rect contains the final bounding +// rect of the PlatformView, the clip mutator is not applied for performance optimization. +// +// This method is only called when the `embeddedView` needs to be re-composited at the current +// frame. See: `compositeView:withParams:` for details. +- (void)applyMutators:(const flutter::MutatorsStack&)mutatorsStack + embeddedView:(UIView*)embeddedView + boundingRect:(const SkRect&)boundingRect; + +// Appends the overlay views and platform view and sets their z index based on the composition +// order. +- (void)bringLayersIntoView:(const LayersMap&)layerMap + withCompositionOrder:(const std::vector&)compositionOrder; + +- (std::shared_ptr)nextLayerInPool; + +/// Runs on the platform thread. +- (void)createLayerWithIosContext:(const std::shared_ptr&)iosContext + grContext:(GrDirectContext*)grContext + pixelFormat:(MTLPixelFormat)pixelFormat; + +/// Removes overlay views and platform views that aren't needed in the current frame. +/// Must run on the platform thread. +- (void)removeUnusedLayers:(const std::vector>&)unusedLayers + withCompositionOrder:(const std::vector&)compositionOrder; + +/// Computes and returns all views to be disposed on the platform thread, removes them from +/// self.platformViews, self.viewsToRecomposite, and self.currentCompositionParams. Any views that +/// still require compositing are not returned, but instead added to `viewsToDelayDispose` for +/// disposal on the next call. +- (std::vector)computeViewsToDispose; + +/// Resets the state of the frame. +- (void)resetFrameState; +@end + +@implementation FlutterPlatformViewsController { + // TODO(cbracken): Replace with Obj-C types and use @property declarations to automatically + // synthesize the ivars. + // + // These ivars are required because we're transitioning the previous C++ implementation to Obj-C. + // We require ivars to declare the concrete types and then wrap with @property declarations that + // return a reference to the ivar, allowing for use like `self.layerPool` and + // `self.slices[viewId] = x`. + std::unique_ptr _layerPool; + std::unordered_map> _slices; + std::unordered_map*> _factories; + std::unordered_map + _gestureRecognizersBlockingPolicies; + fml::RefPtr _platformTaskRunner; + std::unordered_map _platformViews; + std::unordered_map _currentCompositionParams; + std::unordered_set _viewsToDispose; + std::vector _compositionOrder; + std::vector _visitedPlatformViews; + std::unordered_set _viewsToRecomposite; + std::vector _previousCompositionOrder; +} + +- (id)init { + if (self = [super init]) { + _layerPool = std::make_unique(); + _maskViewPool = + [[FlutterClippingMaskViewPool alloc] initWithCapacity:kFlutterClippingMaskViewPoolCapacity]; + _hadPlatformViews = NO; + _canApplyBlurBackdrop = YES; + } + return self; +} + +- (const fml::RefPtr&)taskRunner { + return _platformTaskRunner; +} + +- (void)setTaskRunner:(const fml::RefPtr&)platformTaskRunner { + _platformTaskRunner = platformTaskRunner; +} + +- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { + if ([[call method] isEqualToString:@"create"]) { + [self onCreate:call result:result]; + } else if ([[call method] isEqualToString:@"dispose"]) { + [self onDispose:call result:result]; + } else if ([[call method] isEqualToString:@"acceptGesture"]) { + [self onAcceptGesture:call result:result]; + } else if ([[call method] isEqualToString:@"rejectGesture"]) { + [self onRejectGesture:call result:result]; + } else { + result(FlutterMethodNotImplemented); + } +} + +- (void)onCreate:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary* args = [call arguments]; + + int64_t viewId = [args[@"id"] longLongValue]; + NSString* viewTypeString = args[@"viewType"]; + std::string viewType(viewTypeString.UTF8String); + + if (self.platformViews.count(viewId) != 0) { + result([FlutterError errorWithCode:@"recreating_view" + message:@"trying to create an already created view" + details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); + return; + } + + NSObject* factory = self.factories[viewType]; + if (factory == nil) { + result([FlutterError + errorWithCode:@"unregistered_view_type" + message:[NSString stringWithFormat:@"A UIKitView widget is trying to create a " + @"PlatformView with an unregistered type: < %@ >", + viewTypeString] + details:@"If you are the author of the PlatformView, make sure `registerViewFactory` " + @"is invoked.\n" + @"See: " + @"https://docs.flutter.dev/development/platform-integration/" + @"platform-views#on-the-platform-side-1 for more details.\n" + @"If you are not the author of the PlatformView, make sure to call " + @"`GeneratedPluginRegistrant.register`."]); + return; + } + + id params = nil; + if ([factory respondsToSelector:@selector(createArgsCodec)]) { + NSObject* codec = [factory createArgsCodec]; + if (codec != nil && args[@"params"] != nil) { + FlutterStandardTypedData* paramsData = args[@"params"]; + params = [codec decode:paramsData.data]; + } + } + + NSObject* embeddedView = [factory createWithFrame:CGRectZero + viewIdentifier:viewId + arguments:params]; + UIView* platformView = [embeddedView view]; + // Set a unique view identifier, so the platform view can be identified in unit tests. + platformView.accessibilityIdentifier = [NSString stringWithFormat:@"platform_view[%lld]", viewId]; + + FlutterTouchInterceptingView* touchInterceptor = [[FlutterTouchInterceptingView alloc] + initWithEmbeddedView:platformView + platformViewsController:self + gestureRecognizersBlockingPolicy:self.gestureRecognizersBlockingPolicies[viewType]]; + + ChildClippingView* clippingView = [[ChildClippingView alloc] initWithFrame:CGRectZero]; + [clippingView addSubview:touchInterceptor]; + + self.platformViews.emplace(viewId, PlatformViewData{ + .view = embeddedView, // + .touch_interceptor = touchInterceptor, // + .root_view = clippingView // + }); + + result(nil); +} + +- (void)onDispose:(FlutterMethodCall*)call result:(FlutterResult)result { + NSNumber* arg = [call arguments]; + int64_t viewId = [arg longLongValue]; + + if (self.platformViews.count(viewId) == 0) { + result([FlutterError errorWithCode:@"unknown_view" + message:@"trying to dispose an unknown" + details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); + return; + } + // We wait for next submitFrame to dispose views. + self.viewsToDispose.insert(viewId); + result(nil); +} + +- (void)onAcceptGesture:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary* args = [call arguments]; + int64_t viewId = [args[@"id"] longLongValue]; + + if (self.platformViews.count(viewId) == 0) { + result([FlutterError errorWithCode:@"unknown_view" + message:@"trying to set gesture state for an unknown view" + details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); + return; + } + + FlutterTouchInterceptingView* view = self.platformViews[viewId].touch_interceptor; + [view releaseGesture]; + + result(nil); +} + +- (void)onRejectGesture:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary* args = [call arguments]; + int64_t viewId = [args[@"id"] longLongValue]; + + if (self.platformViews.count(viewId) == 0) { + result([FlutterError errorWithCode:@"unknown_view" + message:@"trying to set gesture state for an unknown view" + details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); + return; + } + + FlutterTouchInterceptingView* view = self.platformViews[viewId].touch_interceptor; + [view blockGesture]; + + result(nil); +} + +- (void)registerViewFactory:(NSObject*)factory + withId:(NSString*)factoryId + gestureRecognizersBlockingPolicy: + (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizerBlockingPolicy { + std::string idString([factoryId UTF8String]); + FML_CHECK(self.factories.count(idString) == 0); + self.factories[idString] = factory; + self.gestureRecognizersBlockingPolicies[idString] = gestureRecognizerBlockingPolicy; +} + +- (void)beginFrameWithSize:(SkISize)frameSize { + [self resetFrameState]; + self.frameSize = frameSize; +} + +- (void)cancelFrame { + [self resetFrameState]; +} + +- (flutter::PostPrerollResult)postPrerollActionWithThreadMerger: + (const fml::RefPtr&)rasterThreadMerger + impellerEnabled:(BOOL)impellerEnabled { + // TODO(jonahwilliams): remove this once Software backend is removed for iOS Sim. +#ifdef FML_OS_IOS_SIMULATOR + const bool mergeThreads = true; +#else + const bool mergeThreads = !impellerEnabled; +#endif // FML_OS_IOS_SIMULATOR + + if (mergeThreads) { + if (self.compositionOrder.empty()) { + return flutter::PostPrerollResult::kSuccess; + } + if (!rasterThreadMerger->IsMerged()) { + // The raster thread merger may be disabled if the rasterizer is being + // created or teared down. + // + // In such cases, the current frame is dropped, and a new frame is attempted + // with the same layer tree. + // + // Eventually, the frame is submitted once this method returns `kSuccess`. + // At that point, the raster tasks are handled on the platform thread. + [self cancelFrame]; + return flutter::PostPrerollResult::kSkipAndRetryFrame; + } + // If the post preroll action is successful, we will display platform views in the current + // frame. In order to sync the rendering of the platform views (quartz) with skia's rendering, + // We need to begin an explicit CATransaction. This transaction needs to be submitted + // after the current frame is submitted. + rasterThreadMerger->ExtendLeaseTo(kDefaultMergedLeaseDuration); + } + return flutter::PostPrerollResult::kSuccess; +} + +- (void)endFrameWithResubmit:(BOOL)shouldResubmitFrame + threadMerger:(const fml::RefPtr&)rasterThreadMerger + impellerEnabled:(BOOL)impellerEnabled { +#if FML_OS_IOS_SIMULATOR + BOOL runCheck = YES; +#else + BOOL runCheck = !impellerEnabled; +#endif // FML_OS_IOS_SIMULATOR + if (runCheck && shouldResubmitFrame) { + rasterThreadMerger->MergeWithLease(kDefaultMergedLeaseDuration); + } +} + +- (void)pushFilterToVisitedPlatformViews:(const std::shared_ptr&)filter + withRect:(const SkRect&)filterRect { + for (int64_t id : self.visitedPlatformViews) { + flutter::EmbeddedViewParams params = self.currentCompositionParams[id]; + params.PushImageFilter(filter, filterRect); + self.currentCompositionParams[id] = params; + } +} + +- (void)prerollCompositeEmbeddedView:(int64_t)viewId + withParams:(std::unique_ptr)params { + SkRect viewBounds = SkRect::Make(self.frameSize); + std::unique_ptr view; + view = std::make_unique(viewBounds); + self.slices.insert_or_assign(viewId, std::move(view)); + + self.compositionOrder.push_back(viewId); + + if (self.currentCompositionParams.count(viewId) == 1 && + self.currentCompositionParams[viewId] == *params.get()) { + // Do nothing if the params didn't change. + return; + } + self.currentCompositionParams[viewId] = flutter::EmbeddedViewParams(*params.get()); + self.viewsToRecomposite.insert(viewId); +} + +- (size_t)embeddedViewCount { + return self.compositionOrder.size(); +} + +- (UIView*)platformViewForId:(int64_t)viewId { + return [self flutterTouchInterceptingViewForId:viewId].embeddedView; +} + +- (FlutterTouchInterceptingView*)flutterTouchInterceptingViewForId:(int64_t)viewId { + if (self.platformViews.empty()) { + return nil; + } + return self.platformViews[viewId].touch_interceptor; +} + +- (long)firstResponderPlatformViewId { + for (auto const& [id, platformViewData] : self.platformViews) { + UIView* rootView = platformViewData.root_view; + if (rootView.flt_hasFirstResponderInViewHierarchySubtree) { + return id; + } + } + return -1; +} + +- (void)clipViewSetMaskView:(UIView*)clipView { + FML_DCHECK([[NSThread currentThread] isMainThread]); + if (clipView.maskView) { + return; + } + CGRect frame = + CGRectMake(-clipView.frame.origin.x, -clipView.frame.origin.y, + CGRectGetWidth(self.flutterView.bounds), CGRectGetHeight(self.flutterView.bounds)); + clipView.maskView = [self.maskViewPool getMaskViewWithFrame:frame]; +} + +- (void)applyMutators:(const flutter::MutatorsStack&)mutatorsStack + embeddedView:(UIView*)embeddedView + boundingRect:(const SkRect&)boundingRect { + if (self.flutterView == nil) { + return; + } + + ResetAnchor(embeddedView.layer); + ChildClippingView* clipView = (ChildClippingView*)embeddedView.superview; + + SkMatrix transformMatrix; + NSMutableArray* blurFilters = [[NSMutableArray alloc] init]; + FML_DCHECK(!clipView.maskView || + [clipView.maskView isKindOfClass:[FlutterClippingMaskView class]]); + if (clipView.maskView) { + [self.maskViewPool insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)]; + clipView.maskView = nil; + } + CGFloat screenScale = [UIScreen mainScreen].scale; + auto iter = mutatorsStack.Begin(); + while (iter != mutatorsStack.End()) { + switch ((*iter)->GetType()) { + case flutter::kTransform: { + transformMatrix.preConcat((*iter)->GetMatrix()); + break; + } + case flutter::kClipRect: { + if (ClipRectContainsPlatformViewBoundingRect((*iter)->GetRect(), boundingRect, + transformMatrix)) { + break; + } + [self clipViewSetMaskView:clipView]; + [(FlutterClippingMaskView*)clipView.maskView clipRect:(*iter)->GetRect() + matrix:transformMatrix]; + break; + } + case flutter::kClipRRect: { + if (ClipRRectContainsPlatformViewBoundingRect((*iter)->GetRRect(), boundingRect, + transformMatrix)) { + break; + } + [self clipViewSetMaskView:clipView]; + [(FlutterClippingMaskView*)clipView.maskView clipRRect:(*iter)->GetRRect() + matrix:transformMatrix]; + break; + } + case flutter::kClipPath: { + // TODO(cyanglaz): Find a way to pre-determine if path contains the PlatformView boudning + // rect. See `ClipRRectContainsPlatformViewBoundingRect`. + // https://github.com/flutter/flutter/issues/118650 + [self clipViewSetMaskView:clipView]; + [(FlutterClippingMaskView*)clipView.maskView clipPath:(*iter)->GetPath() + matrix:transformMatrix]; + break; + } + case flutter::kOpacity: + embeddedView.alpha = (*iter)->GetAlphaFloat() * embeddedView.alpha; + break; + case flutter::kBackdropFilter: { + // Only support DlBlurImageFilter for BackdropFilter. + if (!self.canApplyBlurBackdrop || !(*iter)->GetFilterMutation().GetFilter().asBlur()) { + break; + } + CGRect filterRect = GetCGRectFromSkRect((*iter)->GetFilterMutation().GetFilterRect()); + // `filterRect` is in global coordinates. We need to convert to local space. + filterRect = CGRectApplyAffineTransform( + filterRect, CGAffineTransformMakeScale(1 / screenScale, 1 / screenScale)); + // `filterRect` reprents the rect that should be filtered inside the `_flutterView`. + // The `PlatformViewFilter` needs the frame inside the `clipView` that needs to be + // filtered. + if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) { + break; + } + CGRect intersection = CGRectIntersection(filterRect, clipView.frame); + CGRect frameInClipView = [self.flutterView convertRect:intersection toView:clipView]; + // sigma_x is arbitrarily chosen as the radius value because Quartz sets + // sigma_x and sigma_y equal to each other. DlBlurImageFilter's Tile Mode + // is not supported in Quartz's gaussianBlur CAFilter, so it is not used + // to blur the PlatformView. + CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x(); + UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc] + initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; + PlatformViewFilter* filter = [[PlatformViewFilter alloc] initWithFrame:frameInClipView + blurRadius:blurRadius + visualEffectView:visualEffectView]; + if (!filter) { + self.canApplyBlurBackdrop = NO; + } else { + [blurFilters addObject:filter]; + } + break; + } + } + ++iter; + } + + if (self.canApplyBlurBackdrop) { + [clipView applyBlurBackdropFilters:blurFilters]; + } + + // The UIKit frame is set based on the logical resolution (points) instead of physical. + // (https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html). + // However, flow is based on the physical resolution. For example, 1000 pixels in flow equals + // 500 points in UIKit for devices that has screenScale of 2. We need to scale the transformMatrix + // down to the logical resoltion before applying it to the layer of PlatformView. + transformMatrix.postScale(1 / screenScale, 1 / screenScale); + + // Reverse the offset of the clipView. + // The clipView's frame includes the final translate of the final transform matrix. + // Thus, this translate needs to be reversed so the platform view can layout at the correct + // offset. + // + // Note that the transforms are not applied to the clipping paths because clipping paths happen on + // the mask view, whose origin is always (0,0) to the _flutterView. + transformMatrix.postTranslate(-clipView.frame.origin.x, -clipView.frame.origin.y); + + embeddedView.layer.transform = GetCATransform3DFromSkMatrix(transformMatrix); +} + +- (void)compositeView:(int64_t)viewId withParams:(const flutter::EmbeddedViewParams&)params { + // TODO(https://github.com/flutter/flutter/issues/109700) + CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height()); + FlutterTouchInterceptingView* touchInterceptor = self.platformViews[viewId].touch_interceptor; + touchInterceptor.layer.transform = CATransform3DIdentity; + touchInterceptor.frame = frame; + touchInterceptor.alpha = 1; + + const flutter::MutatorsStack& mutatorStack = params.mutatorsStack(); + UIView* clippingView = self.platformViews[viewId].root_view; + // The frame of the clipping view should be the final bounding rect. + // Because the translate matrix in the Mutator Stack also includes the offset, + // when we apply the transforms matrix in |applyMutators:embeddedView:boundingRect|, we need + // to remember to do a reverse translate. + const SkRect& rect = params.finalBoundingRect(); + CGFloat screenScale = [UIScreen mainScreen].scale; + clippingView.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale, + rect.width() / screenScale, rect.height() / screenScale); + [self applyMutators:mutatorStack embeddedView:touchInterceptor boundingRect:rect]; +} + +- (flutter::DlCanvas*)compositeEmbeddedViewWithId:(int64_t)viewId { + FML_DCHECK(self.slices.find(viewId) != self.slices.end()); + return self.slices[viewId]->canvas(); +} + +- (void)reset { + // Reset will only be called from the raster thread or a merged raster/platform thread. + // _platformViews must only be modified on the platform thread, and any operations that + // read or modify platform views should occur there. + fml::TaskRunner::RunNowOrPostTask(self.platformTaskRunner, [self]() { + for (int64_t viewId : self.compositionOrder) { + [self.platformViews[viewId].root_view removeFromSuperview]; + } + self.platformViews.clear(); + }); + + self.compositionOrder.clear(); + self.slices.clear(); + self.currentCompositionParams.clear(); + self.viewsToRecomposite.clear(); + self.layerPool->RecycleLayers(); + self.visitedPlatformViews.clear(); +} + +- (BOOL)submitFrame:(std::unique_ptr)background_frame + withIosContext:(const std::shared_ptr&)iosContext + grContext:(GrDirectContext*)grContext { + TRACE_EVENT0("flutter", "PlatformViewsController::SubmitFrame"); + + // No platform views to render; we're done. + if (self.flutterView == nil || (self.compositionOrder.empty() && !self.hadPlatformViews)) { + self.hadPlatformViews = NO; + return background_frame->Submit(); + } + self.hadPlatformViews = !self.compositionOrder.empty(); + + bool didEncode = true; + LayersMap platformViewLayers; + std::vector> surfaceFrames; + surfaceFrames.reserve(self.compositionOrder.size()); + std::unordered_map viewRects; + + for (int64_t viewId : self.compositionOrder) { + viewRects[viewId] = self.currentCompositionParams[viewId].finalBoundingRect(); + } + + std::unordered_map overlayLayers = + SliceViews(background_frame->Canvas(), self.compositionOrder, self.slices, viewRects); + + size_t requiredOverlayLayers = 0; + for (int64_t viewId : self.compositionOrder) { + std::unordered_map::const_iterator overlay = overlayLayers.find(viewId); + if (overlay == overlayLayers.end()) { + continue; + } + requiredOverlayLayers++; + } + + // If there are not sufficient overlay layers, we must construct them on the platform + // thread, at least until we've refactored iOS surface creation to use IOSurfaces + // instead of CALayers. + [self createMissingOverlays:requiredOverlayLayers withIosContext:iosContext grContext:grContext]; + + int64_t overlayId = 0; + for (int64_t viewId : self.compositionOrder) { + std::unordered_map::const_iterator overlay = overlayLayers.find(viewId); + if (overlay == overlayLayers.end()) { + continue; + } + std::shared_ptr layer = self.nextLayerInPool; + if (!layer) { + continue; + } + + std::unique_ptr frame = layer->surface->AcquireFrame(self.frameSize); + // If frame is null, AcquireFrame already printed out an error message. + if (!frame) { + continue; + } + flutter::DlCanvas* overlayCanvas = frame->Canvas(); + int restoreCount = overlayCanvas->GetSaveCount(); + overlayCanvas->Save(); + overlayCanvas->ClipRect(overlay->second); + overlayCanvas->Clear(flutter::DlColor::kTransparent()); + self.slices[viewId]->render_into(overlayCanvas); + overlayCanvas->RestoreToCount(restoreCount); + + // This flutter view is never the last in a frame, since we always submit the + // underlay view last. + frame->set_submit_info({.frame_boundary = false, .present_with_transaction = true}); + layer->did_submit_last_frame = frame->Encode(); + + didEncode &= layer->did_submit_last_frame; + platformViewLayers[viewId] = LayerData{ + .rect = overlay->second, // + .view_id = viewId, // + .overlay_id = overlayId, // + .layer = layer // + }; + surfaceFrames.push_back(std::move(frame)); + overlayId++; + } + + auto previousSubmitInfo = background_frame->submit_info(); + background_frame->set_submit_info({ + .frame_damage = previousSubmitInfo.frame_damage, + .buffer_damage = previousSubmitInfo.buffer_damage, + .present_with_transaction = true, + }); + background_frame->Encode(); + surfaceFrames.push_back(std::move(background_frame)); + + // Mark all layers as available, so they can be used in the next frame. + std::vector> unusedLayers = + self.layerPool->RemoveUnusedLayers(); + self.layerPool->RecycleLayers(); + + auto task = [self, // + platformViewLayers = std::move(platformViewLayers), // + currentCompositionParams = self.currentCompositionParams, // + viewsToRecomposite = self.viewsToRecomposite, // + compositionOrder = self.compositionOrder, // + unusedLayers = std::move(unusedLayers), // + surfaceFrames = std::move(surfaceFrames) // + ]() mutable { + [self performSubmit:platformViewLayers + currentCompositionParams:currentCompositionParams + viewsToRecomposite:viewsToRecomposite + compositionOrder:compositionOrder + unusedLayers:unusedLayers + surfaceFrames:surfaceFrames]; + }; + + fml::TaskRunner::RunNowOrPostTask(self.platformTaskRunner, fml::MakeCopyable(std::move(task))); + + return didEncode; +} + +- (void)createMissingOverlays:(size_t)requiredOverlayLayers + withIosContext:(const std::shared_ptr&)iosContext + grContext:(GrDirectContext*)grContext { + TRACE_EVENT0("flutter", "PlatformViewsController::CreateMissingLayers"); + + if (requiredOverlayLayers <= self.layerPool->size()) { + return; + } + auto missingLayerCount = requiredOverlayLayers - self.layerPool->size(); + + // If the raster thread isn't merged, create layers on the platform thread and block until + // complete. + auto latch = std::make_shared(1u); + fml::TaskRunner::RunNowOrPostTask( + self.platformTaskRunner, [self, missingLayerCount, iosContext, grContext, latch]() { + for (auto i = 0u; i < missingLayerCount; i++) { + [self createLayerWithIosContext:iosContext + grContext:grContext + pixelFormat:((FlutterView*)self.flutterView).pixelFormat]; + } + latch->CountDown(); + }); + if (![[NSThread currentThread] isMainThread]) { + latch->Wait(); + } +} + +- (void)performSubmit:(const LayersMap&)platformViewLayers + currentCompositionParams: + (std::unordered_map&)currentCompositionParams + viewsToRecomposite:(const std::unordered_set&)viewsToRecomposite + compositionOrder:(const std::vector&)compositionOrder + unusedLayers: + (const std::vector>&)unusedLayers + surfaceFrames: + (const std::vector>&)surfaceFrames { + TRACE_EVENT0("flutter", "PlatformViewsController::PerformSubmit"); + FML_DCHECK([[NSThread currentThread] isMainThread]); + + [CATransaction begin]; + + // Configure Flutter overlay views. + for (const auto& [viewId, layerData] : platformViewLayers) { + layerData.layer->UpdateViewState(self.flutterView, // + layerData.rect, // + layerData.view_id, // + layerData.overlay_id // + ); + } + + // Dispose unused Flutter Views. + for (auto& view : [self computeViewsToDispose]) { + [view removeFromSuperview]; + } + + // Composite Platform Views. + for (int64_t viewId : viewsToRecomposite) { + [self compositeView:viewId withParams:currentCompositionParams[viewId]]; + } + + // Present callbacks. + for (const auto& frame : surfaceFrames) { + frame->Submit(); + } + + // If a layer was allocated in the previous frame, but it's not used in the current frame, + // then it can be removed from the scene. + [self removeUnusedLayers:unusedLayers withCompositionOrder:compositionOrder]; + + // Organize the layers by their z indexes. + [self bringLayersIntoView:platformViewLayers withCompositionOrder:compositionOrder]; + + [CATransaction commit]; +} + +- (void)bringLayersIntoView:(const LayersMap&)layerMap + withCompositionOrder:(const std::vector&)compositionOrder { + FML_DCHECK(self.flutterView); + UIView* flutterView = self.flutterView; + + self.previousCompositionOrder.clear(); + NSMutableArray* desiredPlatformSubviews = [NSMutableArray array]; + for (int64_t platformViewId : compositionOrder) { + self.previousCompositionOrder.push_back(platformViewId); + UIView* platformViewRoot = self.platformViews[platformViewId].root_view; + if (platformViewRoot != nil) { + [desiredPlatformSubviews addObject:platformViewRoot]; + } + + auto maybeLayerData = layerMap.find(platformViewId); + if (maybeLayerData != layerMap.end()) { + auto view = maybeLayerData->second.layer->overlay_view_wrapper; + if (view != nil) { + [desiredPlatformSubviews addObject:view]; + } + } + } + + NSSet* desiredPlatformSubviewsSet = [NSSet setWithArray:desiredPlatformSubviews]; + NSArray* existingPlatformSubviews = [flutterView.subviews + filteredArrayUsingPredicate:[NSPredicate + predicateWithBlock:^BOOL(id object, NSDictionary* bindings) { + return [desiredPlatformSubviewsSet containsObject:object]; + }]]; + + // Manipulate view hierarchy only if needed, to address a performance issue where + // this method is called even when view hierarchy stays the same. + // See: https://github.com/flutter/flutter/issues/121833 + // TODO(hellohuanlin): investigate if it is possible to skip unnecessary bringLayersIntoView. + if (![desiredPlatformSubviews isEqualToArray:existingPlatformSubviews]) { + for (UIView* subview in desiredPlatformSubviews) { + // `addSubview` will automatically reorder subview if it is already added. + [flutterView addSubview:subview]; + } + } +} + +- (std::shared_ptr)nextLayerInPool { + return self.layerPool->GetNextLayer(); +} + +- (void)createLayerWithIosContext:(const std::shared_ptr&)iosContext + grContext:(GrDirectContext*)grContext + pixelFormat:(MTLPixelFormat)pixelFormat { + self.layerPool->CreateLayer(grContext, iosContext, pixelFormat); +} + +- (void)removeUnusedLayers:(const std::vector>&)unusedLayers + withCompositionOrder:(const std::vector&)compositionOrder { + for (const std::shared_ptr& layer : unusedLayers) { + [layer->overlay_view_wrapper removeFromSuperview]; + } + + std::unordered_set compositionOrderSet; + for (int64_t viewId : compositionOrder) { + compositionOrderSet.insert(viewId); + } + // Remove unused platform views. + for (int64_t viewId : self.previousCompositionOrder) { + if (compositionOrderSet.find(viewId) == compositionOrderSet.end()) { + UIView* platformViewRoot = self.platformViews[viewId].root_view; + [platformViewRoot removeFromSuperview]; + } + } +} + +- (std::vector)computeViewsToDispose { + std::vector views; + if (self.viewsToDispose.empty()) { + return views; + } + + std::unordered_set viewsToComposite(self.compositionOrder.begin(), + self.compositionOrder.end()); + std::unordered_set viewsToDelayDispose; + for (int64_t viewId : self.viewsToDispose) { + if (viewsToComposite.count(viewId)) { + viewsToDelayDispose.insert(viewId); + continue; + } + UIView* rootView = self.platformViews[viewId].root_view; + views.push_back(rootView); + self.currentCompositionParams.erase(viewId); + self.viewsToRecomposite.erase(viewId); + self.platformViews.erase(viewId); + } + self.viewsToDispose = std::move(viewsToDelayDispose); + return views; +} + +- (void)resetFrameState { + self.slices.clear(); + self.compositionOrder.clear(); + self.visitedPlatformViews.clear(); +} + +- (void)pushVisitedPlatformViewId:(int64_t)viewId { + self.visitedPlatformViews.push_back(viewId); +} + +- (const flutter::EmbeddedViewParams&)compositionParamsForView:(int64_t)viewId { + return self.currentCompositionParams.find(viewId)->second; +} + +#pragma mark - Properties + +- (flutter::OverlayLayerPool*)layerPool { + return _layerPool.get(); +} + +- (std::unordered_map>&)slices { + return _slices; +} + +- (std::unordered_map*>&)factories { + return _factories; +} +- (std::unordered_map&) + gestureRecognizersBlockingPolicies { + return _gestureRecognizersBlockingPolicies; +} + +- (std::unordered_map&)platformViews { + return _platformViews; +} + +- (std::unordered_map&)currentCompositionParams { + return _currentCompositionParams; +} + +- (std::unordered_set&)viewsToDispose { + return _viewsToDispose; +} + +- (std::vector&)compositionOrder { + return _compositionOrder; +} + +- (std::vector&)visitedPlatformViews { + return _visitedPlatformViews; +} + +- (std::unordered_set&)viewsToRecomposite { + return _viewsToRecomposite; +} + +- (std::vector&)previousCompositionOrder { + return _previousCompositionOrder; +} + +@end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 8c0bb2b03edca..465aa8d722527 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -2,26 +2,31 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h" + #import #import +#import #import -#include "fml/synchronization/count_down_latch.h" -#include "shell/platform/darwin/ios/framework/Source/platform_views_controller.h" -#import "flutter/display_list/effects/dl_image_filters.h" -#import "flutter/fml/thread.h" +#include + +#include "flutter/display_list/effects/dl_image_filters.h" +#include "flutter/fml/synchronization/count_down_latch.h" +#include "flutter/fml/thread.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" -#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h" -#import "flutter/shell/platform/darwin/ios/platform_view_ios.h" +#include "flutter/shell/platform/darwin/ios/ios_context_noop.h" +#include "flutter/shell/platform/darwin/ios/platform_view_ios.h" FLUTTER_ASSERT_ARC @class FlutterPlatformViewsTestMockPlatformView; -__weak static FlutterPlatformViewsTestMockPlatformView* gMockPlatformView = nil; +__weak static UIView* gMockPlatformView = nil; const float kFloatCompareEpsilon = 0.001; @interface FlutterPlatformViewsTestMockPlatformView : UIView @@ -84,6 +89,45 @@ @implementation FlutterPlatformViewsTestMockFlutterPlatformFactory @end +@interface FlutterPlatformViewsTestMockWebView : NSObject +@property(nonatomic, strong) UIView* view; +@property(nonatomic, assign) BOOL viewCreated; +@end + +@implementation FlutterPlatformViewsTestMockWebView +- (instancetype)init { + if (self = [super init]) { + _view = [[WKWebView alloc] init]; + gMockPlatformView = _view; + _viewCreated = NO; + } + return self; +} + +- (UIView*)view { + [self checkViewCreatedOnce]; + return _view; +} + +- (void)checkViewCreatedOnce { + if (self.viewCreated) { + abort(); + } + self.viewCreated = YES; +} +@end + +@interface FlutterPlatformViewsTestMockWebViewFactory : NSObject +@end + +@implementation FlutterPlatformViewsTestMockWebViewFactory +- (NSObject*)createWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args { + return [[FlutterPlatformViewsTestMockWebView alloc] init]; +} +@end + @interface FlutterPlatformViewsTestNilFlutterPlatformFactory : NSObject @end @@ -163,8 +207,9 @@ - (void)testFlutterViewOnlyCreateOnceInOneFrame { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -177,18 +222,21 @@ - (void)testFlutterViewOnlyCreateOnceInOneFrame { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -204,11 +252,12 @@ - (void)testFlutterViewOnlyCreateOnceInOneFrame { auto embeddedViewParams = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; XCTAssertNotNil(gMockPlatformView); - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; } - (void)testCanCreatePlatformViewWithoutFlutterView { @@ -219,8 +268,9 @@ - (void)testCanCreatePlatformViewWithoutFlutterView { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -233,16 +283,19 @@ - (void)testCanCreatePlatformViewWithoutFlutterView { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); } @@ -312,8 +365,9 @@ - (void)testApplyBackdropFilter { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -326,21 +380,24 @@ - (void)testApplyBackdropFilter { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -354,9 +411,11 @@ - (void)testApplyBackdropFilter { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -389,8 +448,9 @@ - (void)testApplyBackdropFilterWithCorrectFrame { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -403,21 +463,24 @@ - (void)testApplyBackdropFilterWithCorrectFrame { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -431,9 +494,11 @@ - (void)testApplyBackdropFilterWithCorrectFrame { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(5, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -466,8 +531,9 @@ - (void)testApplyMultipleBackdropFilters { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -480,21 +546,24 @@ - (void)testApplyMultipleBackdropFilters { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -510,9 +579,11 @@ - (void)testApplyMultipleBackdropFilters { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(20, 20), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -544,8 +615,9 @@ - (void)testAddBackdropFilters { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -558,21 +630,24 @@ - (void)testAddBackdropFilters { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -586,9 +661,11 @@ - (void)testAddBackdropFilters { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -625,9 +702,11 @@ - (void)testAddBackdropFilters { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -665,8 +744,9 @@ - (void)testRemoveBackdropFilters { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -679,21 +759,24 @@ - (void)testRemoveBackdropFilters { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -709,9 +792,11 @@ - (void)testRemoveBackdropFilters { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -746,9 +831,11 @@ - (void)testRemoveBackdropFilters { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -787,9 +874,11 @@ - (void)testRemoveBackdropFilters { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -811,8 +900,9 @@ - (void)testEditBackdropFilters { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -825,21 +915,24 @@ - (void)testEditBackdropFilters { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -855,9 +948,11 @@ - (void)testEditBackdropFilters { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -900,9 +995,11 @@ - (void)testEditBackdropFilters { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -955,9 +1052,11 @@ - (void)testEditBackdropFilters { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -1008,9 +1107,11 @@ - (void)testEditBackdropFilters { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -1058,9 +1159,11 @@ - (void)testEditBackdropFilters { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -1098,8 +1201,9 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1112,21 +1216,24 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -1140,9 +1247,11 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -1182,9 +1291,11 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -1223,9 +1334,11 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -1264,9 +1377,11 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -1299,9 +1414,11 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; [flutterView setNeedsLayout]; [flutterView layoutIfNeeded]; @@ -1417,8 +1534,9 @@ - (void)testCompositePlatformView { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1431,21 +1549,24 @@ - (void)testCompositePlatformView { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -1461,9 +1582,11 @@ - (void)testCompositePlatformView { auto embeddedViewParams = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; CGRect platformViewRectInFlutterView = [gMockPlatformView convertRect:gMockPlatformView.bounds toView:flutterView]; @@ -1478,8 +1601,9 @@ - (void)testBackdropFilterCorrectlyPushedAndReset { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1492,21 +1616,24 @@ - (void)testBackdropFilterCorrectlyPushedAndReset { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -1517,14 +1644,17 @@ - (void)testBackdropFilterCorrectlyPushedAndReset { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->BeginFrame(SkISize::Make(0, 0)); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->PushVisitedPlatformView(2); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(0, 0)]; + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController pushVisitedPlatformViewId:2]; auto filter = flutter::DlBlurImageFilter::Make(5, 2, flutter::DlTileMode::kClamp); - flutterPlatformViewsController->PushFilterToVisitedPlatformViews( - filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController + pushFilterToVisitedPlatformViews:filter + withRect:SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -1551,10 +1681,12 @@ - (void)testBackdropFilterCorrectlyPushedAndReset { // New frame, with no filter pushed. auto embeddedViewParams2 = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->BeginFrame(SkISize::Make(0, 0)); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams2)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(0, 0)]; + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams2)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); @@ -1579,8 +1711,9 @@ - (void)testChildClippingViewShouldBeTheBoundingRectOfPlatformView { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1593,21 +1726,24 @@ - (void)testChildClippingViewShouldBeTheBoundingRectOfPlatformView { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -1624,9 +1760,11 @@ - (void)testChildClippingViewShouldBeTheBoundingRectOfPlatformView { auto embeddedViewParams = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; CGRect platformViewRectInFlutterView = [gMockPlatformView convertRect:gMockPlatformView.bounds toView:flutterView]; @@ -1655,8 +1793,9 @@ - (void)testClipsDoNotInterceptWithPlatformViewShouldNotAddMaskView { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1669,21 +1808,24 @@ - (void)testClipsDoNotInterceptWithPlatformViewShouldNotAddMaskView { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params. flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack. @@ -1705,9 +1847,11 @@ - (void)testClipsDoNotInterceptWithPlatformViewShouldNotAddMaskView { auto embeddedViewParams = std::make_unique( SkMatrix::Concat(screenScaleMatrix, translateMatrix), SkSize::Make(5, 5), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; gMockPlatformView.backgroundColor = UIColor.redColor; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); @@ -1727,8 +1871,9 @@ - (void)testClipRRectOnlyHasCornersInterceptWithPlatformViewShouldAddMaskView { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1741,21 +1886,24 @@ - (void)testClipRRectOnlyHasCornersInterceptWithPlatformViewShouldAddMaskView { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack. @@ -1775,9 +1923,11 @@ - (void)testClipRRectOnlyHasCornersInterceptWithPlatformViewShouldAddMaskView { auto embeddedViewParams = std::make_unique( SkMatrix::Concat(screenScaleMatrix, translateMatrix), SkSize::Make(5, 5), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; gMockPlatformView.backgroundColor = UIColor.redColor; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); @@ -1798,8 +1948,9 @@ - (void)testClipRect { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1812,21 +1963,24 @@ - (void)testClipRect { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -1840,9 +1994,11 @@ - (void)testClipRect { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; gMockPlatformView.backgroundColor = UIColor.redColor; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); @@ -1874,8 +2030,9 @@ - (void)testClipRect_multipleClips { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1888,21 +2045,24 @@ - (void)testClipRect_multipleClips { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -1919,9 +2079,11 @@ - (void)testClipRect_multipleClips { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; gMockPlatformView.backgroundColor = UIColor.redColor; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); @@ -1970,8 +2132,9 @@ - (void)testClipRRect { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -1984,21 +2147,24 @@ - (void)testClipRRect { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -2012,9 +2178,11 @@ - (void)testClipRRect { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; gMockPlatformView.backgroundColor = UIColor.redColor; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); @@ -2073,8 +2241,9 @@ - (void)testClipRRect_multipleClips { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2087,21 +2256,24 @@ - (void)testClipRRect_multipleClips { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -2118,9 +2290,11 @@ - (void)testClipRRect_multipleClips { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; gMockPlatformView.backgroundColor = UIColor.redColor; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); @@ -2193,8 +2367,9 @@ - (void)testClipPath { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2207,21 +2382,24 @@ - (void)testClipPath { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -2236,9 +2414,11 @@ - (void)testClipPath { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; gMockPlatformView.backgroundColor = UIColor.redColor; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); @@ -2297,8 +2477,9 @@ - (void)testClipPath_multipleClips { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2311,21 +2492,24 @@ - (void)testClipPath_multipleClips { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -2343,9 +2527,11 @@ - (void)testClipPath_multipleClips { auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; gMockPlatformView.backgroundColor = UIColor.redColor; XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); @@ -2418,8 +2604,9 @@ - (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2432,16 +2619,19 @@ - (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); @@ -2472,7 +2662,7 @@ - (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents { // Set flutter view controller allows events to be dispatched. NSSet* touches2 = [[NSSet alloc] init]; id event2 = OCMClassMock([UIEvent class]); - flutterPlatformViewsController->SetFlutterViewController(flutterViewController); + flutterPlatformViewsController.flutterViewController = flutterViewController; [forwardGectureRecognizer touchesBegan:touches2 withEvent:event2]; OCMVerify([flutterViewController touchesBegan:touches2 withEvent:event2]); } @@ -2485,8 +2675,9 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2499,16 +2690,19 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); @@ -2531,14 +2725,14 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu id flutterViewController = OCMClassMock([FlutterViewController class]); { // ***** Sequence 1, finishing touch event with touchEnded ***** // - flutterPlatformViewsController->SetFlutterViewController(flutterViewController); + flutterPlatformViewsController.flutterViewController = flutterViewController; NSSet* touches1 = [[NSSet alloc] init]; id event1 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1]; OCMVerify([flutterViewController touchesBegan:touches1 withEvent:event1]); - flutterPlatformViewsController->SetFlutterViewController(nil); + flutterPlatformViewsController.flutterViewController = nil; // Allow the touch events to finish NSSet* touches2 = [[NSSet alloc] init]; @@ -2565,14 +2759,14 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu { // ***** Sequence 2, finishing touch event with touchCancelled ***** // - flutterPlatformViewsController->SetFlutterViewController(flutterViewController); + flutterPlatformViewsController.flutterViewController = flutterViewController; NSSet* touches1 = [[NSSet alloc] init]; id event1 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1]; OCMVerify([flutterViewController touchesBegan:touches1 withEvent:event1]); - flutterPlatformViewsController->SetFlutterViewController(nil); + flutterPlatformViewsController.flutterViewController = nil; // Allow the touch events to finish NSSet* touches2 = [[NSSet alloc] init]; @@ -2597,7 +2791,7 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu OCMReject([flutterViewController touchesEnded:touches5 withEvent:event5]); } - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; } - (void) @@ -2609,8 +2803,9 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2623,16 +2818,19 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); @@ -2653,8 +2851,7 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu } } id flutterViewController = OCMClassMock([FlutterViewController class]); - - flutterPlatformViewsController->SetFlutterViewController(flutterViewController); + flutterPlatformViewsController.flutterViewController = flutterViewController; // The touches in this sequence requires 1 touch object, we always create the NSSet with one item. NSSet* touches1 = [NSSet setWithObject:@1]; @@ -2663,7 +2860,7 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu OCMVerify([flutterViewController touchesBegan:touches1 withEvent:event1]); FlutterViewController* flutterViewController2 = OCMClassMock([FlutterViewController class]); - flutterPlatformViewsController->SetFlutterViewController(flutterViewController2); + flutterPlatformViewsController.flutterViewController = flutterViewController2; // Touch events should still send to the old FlutterViewController if FlutterViewController // is updated in between. @@ -2712,7 +2909,7 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu OCMVerify([flutterViewController2 touchesEnded:touches8 withEvent:event8]); OCMReject([flutterViewController touchesEnded:touches8 withEvent:event8]); - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; } - (void)testFlutterPlatformViewTouchesCancelledEventAreForcedToBeCancelled { @@ -2723,8 +2920,9 @@ - (void)testFlutterPlatformViewTouchesCancelledEventAreForcedToBeCancelled { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2737,16 +2935,19 @@ - (void)testFlutterPlatformViewTouchesCancelledEventAreForcedToBeCancelled { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); @@ -2767,8 +2968,7 @@ - (void)testFlutterPlatformViewTouchesCancelledEventAreForcedToBeCancelled { } } id flutterViewController = OCMClassMock([FlutterViewController class]); - - flutterPlatformViewsController->SetFlutterViewController(flutterViewController); + flutterPlatformViewsController.flutterViewController = flutterViewController; NSSet* touches1 = [NSSet setWithObject:@1]; id event1 = OCMClassMock([UIEvent class]); @@ -2777,7 +2977,7 @@ - (void)testFlutterPlatformViewTouchesCancelledEventAreForcedToBeCancelled { [forwardGectureRecognizer touchesCancelled:touches1 withEvent:event1]; OCMVerify([flutterViewController forceTouchesCancelled:touches1]); - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; } - (void)testFlutterPlatformViewTouchesEndedOrTouchesCancelledEventDoesNotFailTheGestureRecognizer { @@ -2788,8 +2988,9 @@ - (void)testFlutterPlatformViewTouchesEndedOrTouchesCancelledEventDoesNotFailThe /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2802,16 +3003,19 @@ - (void)testFlutterPlatformViewTouchesEndedOrTouchesCancelledEventDoesNotFailThe FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); @@ -2832,8 +3036,7 @@ - (void)testFlutterPlatformViewTouchesEndedOrTouchesCancelledEventDoesNotFailThe } } id flutterViewController = OCMClassMock([FlutterViewController class]); - - flutterPlatformViewsController->SetFlutterViewController(flutterViewController); + flutterPlatformViewsController.flutterViewController = flutterViewController; NSSet* touches1 = [NSSet setWithObject:@1]; id event1 = OCMClassMock([UIEvent class]); @@ -2882,7 +3085,133 @@ - (void)testFlutterPlatformViewTouchesEndedOrTouchesCancelledEventDoesNotFailThe }); [self waitForExpectationsWithTimeout:30 handler:nil]; - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; +} + +- (void) + testFlutterPlatformViewBlockGestureUnderEagerPolicyShouldRemoveAndAddBackDelayingRecognizerForWebView { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/GetDefaultTaskRunner(), + /*raster=*/GetDefaultTaskRunner(), + /*ui=*/GetDefaultTaskRunner(), + /*io=*/GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); + auto platform_view = std::make_unique( + /*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()); + + FlutterPlatformViewsTestMockWebViewFactory* factory = + [[FlutterPlatformViewsTestMockWebViewFactory alloc] init]; + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockWebView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; + FlutterResult result = ^(id result) { + }; + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall + methodCallWithMethodName:@"create" + arguments:@{@"id" : @2, @"viewType" : @"MockWebView"}] + result:result]; + + XCTAssertNotNil(gMockPlatformView); + + // Find touch inteceptor view + UIView* touchInteceptorView = gMockPlatformView; + while (touchInteceptorView != nil && + ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) { + touchInteceptorView = touchInteceptorView.superview; + } + XCTAssertNotNil(touchInteceptorView); + + XCTAssert(touchInteceptorView.gestureRecognizers.count == 2); + UIGestureRecognizer* delayingRecognizer = touchInteceptorView.gestureRecognizers[0]; + UIGestureRecognizer* forwardingRecognizer = touchInteceptorView.gestureRecognizers[1]; + + XCTAssert([delayingRecognizer isKindOfClass:[FlutterDelayingGestureRecognizer class]]); + XCTAssert([forwardingRecognizer isKindOfClass:[ForwardingGestureRecognizer class]]); + + [(FlutterTouchInterceptingView*)touchInteceptorView blockGesture]; + + if (@available(iOS 18.2, *)) { + // Since we remove and add back delayingRecognizer, it would be reordered to the last. + XCTAssertEqual(touchInteceptorView.gestureRecognizers[0], forwardingRecognizer); + XCTAssertEqual(touchInteceptorView.gestureRecognizers[1], delayingRecognizer); + } else { + XCTAssertEqual(touchInteceptorView.gestureRecognizers[0], delayingRecognizer); + XCTAssertEqual(touchInteceptorView.gestureRecognizers[1], forwardingRecognizer); + } +} + +- (void) + testFlutterPlatformViewBlockGestureUnderEagerPolicyShouldNotRemoveAndAddBackDelayingRecognizerForNonWebView { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/GetDefaultTaskRunner(), + /*raster=*/GetDefaultTaskRunner(), + /*ui=*/GetDefaultTaskRunner(), + /*io=*/GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); + auto platform_view = std::make_unique( + /*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()); + + FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = + [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; + FlutterResult result = ^(id result) { + }; + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; + + XCTAssertNotNil(gMockPlatformView); + + // Find touch inteceptor view + UIView* touchInteceptorView = gMockPlatformView; + while (touchInteceptorView != nil && + ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) { + touchInteceptorView = touchInteceptorView.superview; + } + XCTAssertNotNil(touchInteceptorView); + + XCTAssert(touchInteceptorView.gestureRecognizers.count == 2); + UIGestureRecognizer* delayingRecognizer = touchInteceptorView.gestureRecognizers[0]; + UIGestureRecognizer* forwardingRecognizer = touchInteceptorView.gestureRecognizers[1]; + + XCTAssert([delayingRecognizer isKindOfClass:[FlutterDelayingGestureRecognizer class]]); + XCTAssert([forwardingRecognizer isKindOfClass:[ForwardingGestureRecognizer class]]); + + [(FlutterTouchInterceptingView*)touchInteceptorView blockGesture]; + + XCTAssertEqual(touchInteceptorView.gestureRecognizers[0], delayingRecognizer); + XCTAssertEqual(touchInteceptorView.gestureRecognizers[1], forwardingRecognizer); } - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing { @@ -2893,8 +3222,9 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2907,16 +3237,19 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); @@ -2927,9 +3260,11 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin auto embeddedViewParams_1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams_1)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams_1)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; flutter::SurfaceFrame::FramebufferInfo framebuffer_info; auto mock_surface = std::make_unique( @@ -2937,22 +3272,28 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return false; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - XCTAssertFalse( - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); + XCTAssertFalse([flutterPlatformViewsController + submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]); auto embeddedViewParams_2 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams_2)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams_2)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; auto mock_surface_submit_true = std::make_unique( nullptr, framebuffer_info, [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - XCTAssertTrue(flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, - std::move(mock_surface_submit_true))); + XCTAssertTrue([flutterPlatformViewsController + submitFrame:std::move(mock_surface_submit_true) + withIosContext:std::make_shared() + grContext:nil]); } - (void) @@ -2964,8 +3305,9 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2977,34 +3319,38 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin /*is_gpu_disabled_jsync_switch=*/std::make_shared()); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; // autorelease pool to trigger an autorelease for all the root_views_ and touch_interceptors_. @autoreleasepool { - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; flutter::MutatorsStack stack; SkMatrix finalMatrix; auto embeddedViewParams = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; - // Not calling |flutterPlatformViewsController::SubmitFrame| so that the platform views are not - // added to flutter_view_. + // Not calling |[flutterPlatformViewsController submitFrame:withIosContext:grContext:]| so that + // the platform views are not added to flutter_view_. XCTAssertNotNil(gMockPlatformView); - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; } XCTAssertNil(gMockPlatformView); } @@ -3017,8 +3363,9 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3030,45 +3377,52 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { /*is_gpu_disabled_jsync_switch=*/std::make_shared()); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @0, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; - // First frame, |EmbeddedViewCount| is not empty after composite. - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); + // First frame, |embeddedViewCount| is not empty after composite. + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; flutter::MutatorsStack stack; SkMatrix finalMatrix; auto embeddedViewParams1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1)); - flutterPlatformViewsController->CompositeWithParams( - 0, flutterPlatformViewsController->GetCompositionParams(0)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:0 + withParams:std::move(embeddedViewParams1)]; + [flutterPlatformViewsController + compositeView:0 + withParams:[flutterPlatformViewsController compositionParamsForView:0]]; - XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 1UL); + XCTAssertEqual(flutterPlatformViewsController.embeddedViewCount, 1UL); - // Second frame, |EmbeddedViewCount| should be empty at the start - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); - XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 0UL); + // Second frame, |embeddedViewCount| should be empty at the start + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; + XCTAssertEqual(flutterPlatformViewsController.embeddedViewCount, 0UL); auto embeddedViewParams2 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams2)); - flutterPlatformViewsController->CompositeWithParams( - 0, flutterPlatformViewsController->GetCompositionParams(0)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:0 + withParams:std::move(embeddedViewParams2)]; + [flutterPlatformViewsController + compositeView:0 + withParams:[flutterPlatformViewsController compositionParamsForView:0]]; - XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 1UL); + XCTAssertEqual(flutterPlatformViewsController.embeddedViewCount, 1UL); } - (void) @@ -3080,8 +3434,9 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3093,40 +3448,47 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { /*is_gpu_disabled_jsync_switch=*/std::make_shared()); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @0, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* view1 = gMockPlatformView; // This overwrites `gMockPlatformView` to another view. - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @1, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* view2 = gMockPlatformView; - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; flutter::MutatorsStack stack; SkMatrix finalMatrix; auto embeddedViewParams1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:0 + withParams:std::move(embeddedViewParams1)]; auto embeddedViewParams2 = std::make_unique(finalMatrix, SkSize::Make(500, 500), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams2)]; // SKSurface is required if the root FlutterView is present. const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000); @@ -3137,9 +3499,10 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - - XCTAssertTrue( - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); + XCTAssertTrue([flutterPlatformViewsController + submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]); // platform view is wrapped by touch interceptor, which itself is wrapped by clipping view. UIView* clippingView1 = view1.superview.superview; @@ -3149,15 +3512,17 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { @"The first clipping view should be added before the second clipping view."); // Need to recreate these params since they are `std::move`ed. - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; // Process the second frame in the opposite order. embeddedViewParams2 = std::make_unique(finalMatrix, SkSize::Make(500, 500), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams2)]; embeddedViewParams1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:0 + withParams:std::move(embeddedViewParams1)]; mock_sk_surface = SkSurfaces::Raster(image_info); mock_surface = std::make_unique( @@ -3165,8 +3530,10 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - XCTAssertTrue( - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); + XCTAssertTrue([flutterPlatformViewsController + submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]); XCTAssertTrue([flutterView.subviews indexOfObject:clippingView1] > [flutterView.subviews indexOfObject:clippingView2], @@ -3182,8 +3549,9 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3195,40 +3563,47 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { /*is_gpu_disabled_jsync_switch=*/std::make_shared()); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @0, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* view1 = gMockPlatformView; // This overwrites `gMockPlatformView` to another view. - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @1, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* view2 = gMockPlatformView; - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; flutter::MutatorsStack stack; SkMatrix finalMatrix; auto embeddedViewParams1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:0 + withParams:std::move(embeddedViewParams1)]; auto embeddedViewParams2 = std::make_unique(finalMatrix, SkSize::Make(500, 500), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams2)]; // SKSurface is required if the root FlutterView is present. const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000); @@ -3239,9 +3614,10 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - - XCTAssertTrue( - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); + XCTAssertTrue([flutterPlatformViewsController + submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]); // platform view is wrapped by touch interceptor, which itself is wrapped by clipping view. UIView* clippingView1 = view1.superview.superview; @@ -3251,15 +3627,17 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { @"The first clipping view should be added before the second clipping view."); // Need to recreate these params since they are `std::move`ed. - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; // Process the second frame in the same order. embeddedViewParams1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:0 + withParams:std::move(embeddedViewParams1)]; embeddedViewParams2 = std::make_unique(finalMatrix, SkSize::Make(500, 500), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams2)]; mock_sk_surface = SkSurfaces::Raster(image_info); mock_surface = std::make_unique( @@ -3267,8 +3645,10 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - XCTAssertTrue( - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); + XCTAssertTrue([flutterPlatformViewsController + submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]); XCTAssertTrue([flutterView.subviews indexOfObject:clippingView1] < [flutterView.subviews indexOfObject:clippingView2], @@ -3369,8 +3749,9 @@ - (void)testClipMaskViewIsReused { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3383,20 +3764,23 @@ - (void)testClipMaskViewIsReused { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @1, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack1; // Layer tree always pushes a screen scale factor to the stack @@ -3410,39 +3794,47 @@ - (void)testClipMaskViewIsReused { auto embeddedViewParams1 = std::make_unique( screenScaleMatrix, SkSize::Make(10, 10), stack1); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1)); - flutterPlatformViewsController->CompositeWithParams( - 1, flutterPlatformViewsController->GetCompositionParams(1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams1)]; + [flutterPlatformViewsController + compositeView:1 + withParams:[flutterPlatformViewsController compositionParamsForView:1]]; UIView* childClippingView1 = gMockPlatformView.superview.superview; UIView* maskView1 = childClippingView1.maskView; XCTAssertNotNil(maskView1); // Composite a new frame. - flutterPlatformViewsController->BeginFrame(SkISize::Make(100, 100)); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(100, 100)]; flutter::MutatorsStack stack2; auto embeddedViewParams2 = std::make_unique( screenScaleMatrix, SkSize::Make(10, 10), stack2); auto embeddedViewParams3 = std::make_unique( screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams3)); - flutterPlatformViewsController->CompositeWithParams( - 1, flutterPlatformViewsController->GetCompositionParams(1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams3)]; + [flutterPlatformViewsController + compositeView:1 + withParams:[flutterPlatformViewsController compositionParamsForView:1]]; childClippingView1 = gMockPlatformView.superview.superview; // This overrides gMockPlatformView to point to the newly created platform view. - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; auto embeddedViewParams4 = std::make_unique( screenScaleMatrix, SkSize::Make(10, 10), stack1); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams4)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams4)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; UIView* childClippingView2 = gMockPlatformView.superview.superview; @@ -3460,8 +3852,9 @@ - (void)testDifferentClipMaskViewIsUsedForEachView { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3474,30 +3867,35 @@ - (void)testDifferentClipMaskViewIsUsedForEachView { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @1, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* view1 = gMockPlatformView; // This overwrites `gMockPlatformView` to another view. - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* view2 = gMockPlatformView; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack1; // Layer tree always pushes a screen scale factor to the stack @@ -3516,15 +3914,19 @@ - (void)testDifferentClipMaskViewIsUsedForEachView { auto embeddedViewParams2 = std::make_unique( screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1)); - flutterPlatformViewsController->CompositeWithParams( - 1, flutterPlatformViewsController->GetCompositionParams(1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams1)]; + [flutterPlatformViewsController + compositeView:1 + withParams:[flutterPlatformViewsController compositionParamsForView:1]]; UIView* childClippingView1 = view1.superview.superview; - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams2)); - flutterPlatformViewsController->CompositeWithParams( - 2, flutterPlatformViewsController->GetCompositionParams(2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams2)]; + [flutterPlatformViewsController + compositeView:2 + withParams:[flutterPlatformViewsController compositionParamsForView:2]]; UIView* childClippingView2 = view2.superview.superview; UIView* maskView1 = childClippingView1.maskView; @@ -3540,8 +3942,9 @@ - (void)testMaskViewUsesCAShapeLayerAsTheBackingLayer { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3554,21 +3957,24 @@ - (void)testMaskViewUsesCAShapeLayerAsTheBackingLayer { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @1, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; XCTAssertNotNil(gMockPlatformView); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack1; // Layer tree always pushes a screen scale factor to the stack @@ -3587,9 +3993,11 @@ - (void)testMaskViewUsesCAShapeLayerAsTheBackingLayer { auto embeddedViewParams2 = std::make_unique( screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1)); - flutterPlatformViewsController->CompositeWithParams( - 1, flutterPlatformViewsController->GetCompositionParams(1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams1)]; + [flutterPlatformViewsController + compositeView:1 + withParams:[flutterPlatformViewsController compositionParamsForView:1]]; UIView* childClippingView = gMockPlatformView.superview.superview; @@ -3633,8 +4041,9 @@ - (void)testDisposingViewInCompositionOrderDoNotCrash { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3646,50 +4055,58 @@ - (void)testDisposingViewInCompositionOrderDoNotCrash { /*is_gpu_disabled_jsync_switch=*/std::make_shared()); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}], - result); - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @0, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @1, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; { // **** First frame, view id 0, 1 in the composition_order_, disposing view 0 is called. **** // // No view should be disposed, or removed from the composition order. - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; flutter::MutatorsStack stack; SkMatrix finalMatrix; auto embeddedViewParams0 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams0)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:0 + withParams:std::move(embeddedViewParams0)]; auto embeddedViewParams1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams1)]; - XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 2UL); + XCTAssertEqual(flutterPlatformViewsController.embeddedViewCount, 2UL); XCTestExpectation* expectation = [self expectationWithDescription:@"dispose call ended."]; FlutterResult disposeResult = ^(id result) { [expectation fulfill]; }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall methodCallWithMethodName:@"dispose" arguments:@0], disposeResult); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"dispose" arguments:@0] + result:disposeResult]; [self waitForExpectationsWithTimeout:30 handler:nil]; const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000); @@ -3700,24 +4117,27 @@ - (void)testDisposingViewInCompositionOrderDoNotCrash { [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - XCTAssertTrue( - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); + XCTAssertTrue([flutterPlatformViewsController + submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]); // Disposing won't remove embedded views until the view is removed from the composition_order_ - XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 2UL); - XCTAssertNotNil(flutterPlatformViewsController->GetPlatformViewByID(0)); - XCTAssertNotNil(flutterPlatformViewsController->GetPlatformViewByID(1)); + XCTAssertEqual(flutterPlatformViewsController.embeddedViewCount, 2UL); + XCTAssertNotNil([flutterPlatformViewsController platformViewForId:0]); + XCTAssertNotNil([flutterPlatformViewsController platformViewForId:1]); } { // **** Second frame, view id 1 in the composition_order_, no disposing view is called, **** // // View 0 is removed from the composition order in this frame, hence also disposed. - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; flutter::MutatorsStack stack; SkMatrix finalMatrix; auto embeddedViewParams1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams1)]; const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000); sk_sp mock_sk_surface = SkSurfaces::Raster(image_info); @@ -3727,13 +4147,15 @@ - (void)testDisposingViewInCompositionOrderDoNotCrash { [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - XCTAssertTrue( - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); + XCTAssertTrue([flutterPlatformViewsController + submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]); // Disposing won't remove embedded views until the view is removed from the composition_order_ - XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 1UL); - XCTAssertNil(flutterPlatformViewsController->GetPlatformViewByID(0)); - XCTAssertNotNil(flutterPlatformViewsController->GetPlatformViewByID(1)); + XCTAssertEqual(flutterPlatformViewsController.embeddedViewCount, 1UL); + XCTAssertNil([flutterPlatformViewsController platformViewForId:0]); + XCTAssertNotNil([flutterPlatformViewsController platformViewForId:1]); } } - (void)testOnlyPlatformViewsAreRemovedWhenReset { @@ -3744,8 +4166,9 @@ - (void)testOnlyPlatformViewsAreRemovedWhenReset { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3758,18 +4181,21 @@ - (void)testOnlyPlatformViewsAreRemovedWhenReset { FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; // Layer tree always pushes a screen scale factor to the stack @@ -3785,7 +4211,8 @@ - (void)testOnlyPlatformViewsAreRemovedWhenReset { auto embeddedViewParams = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; // SKSurface is required if the root FlutterView is present. const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000); @@ -3796,13 +4223,14 @@ - (void)testOnlyPlatformViewsAreRemovedWhenReset { [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)); + [flutterPlatformViewsController submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]; UIView* someView = [[UIView alloc] init]; [flutterView addSubview:someView]; - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; XCTAssertEqual(flutterView.subviews.count, 1u); XCTAssertEqual(flutterView.subviews.firstObject, someView); } @@ -3815,8 +4243,9 @@ - (void)testNilPlatformViewDoesntCrash { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3829,18 +4258,21 @@ - (void)testNilPlatformViewDoesntCrash { FlutterPlatformViewsTestNilFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestNilFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; // Create embedded view params flutter::MutatorsStack stack; @@ -3857,7 +4289,8 @@ - (void)testNilPlatformViewDoesntCrash { auto embeddedViewParams = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:2 + withParams:std::move(embeddedViewParams)]; // SKSurface is required if the root FlutterView is present. const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000); @@ -3868,8 +4301,9 @@ - (void)testNilPlatformViewDoesntCrash { [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; }, [](const flutter::SurfaceFrame& surface_frame) { return true; }, /*frame_size=*/SkISize::Make(800, 600)); - - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)); + [flutterPlatformViewsController submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]; XCTAssertEqual(flutterView.subviews.count, 1u); } @@ -3915,8 +4349,9 @@ - (void)testFlutterPlatformViewControllerSubmitFramePreservingFrameDamage { /*raster=*/GetDefaultTaskRunner(), /*ui=*/GetDefaultTaskRunner(), /*io=*/GetDefaultTaskRunner()); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner(); auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -3928,38 +4363,45 @@ - (void)testFlutterPlatformViewControllerSubmitFramePreservingFrameDamage { /*is_gpu_disabled_jsync_switch=*/std::make_shared()); UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)]; - flutterPlatformViewsController->SetFlutterView(flutterView); + flutterPlatformViewsController.flutterView = flutterView; FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @0, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; // This overwrites `gMockPlatformView` to another view. - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}], - result); - - flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @1, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; + + [flutterPlatformViewsController beginFrameWithSize:SkISize::Make(300, 300)]; flutter::MutatorsStack stack; SkMatrix finalMatrix; auto embeddedViewParams1 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:0 + withParams:std::move(embeddedViewParams1)]; auto embeddedViewParams2 = std::make_unique(finalMatrix, SkSize::Make(500, 500), stack); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2)); + [flutterPlatformViewsController prerollCompositeEmbeddedView:1 + withParams:std::move(embeddedViewParams2)]; // SKSurface is required if the root FlutterView is present. const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000); @@ -3979,8 +4421,9 @@ - (void)testFlutterPlatformViewControllerSubmitFramePreservingFrameDamage { .buffer_damage = SkIRect::MakeWH(400, 600), }); - XCTAssertTrue( - flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); + [flutterPlatformViewsController submitFrame:std::move(mock_surface) + withIosContext:std::make_shared() + grContext:nil]; XCTAssertTrue(submit_info.has_value()); XCTAssertEqual(*submit_info->frame_damage, SkIRect::MakeWH(800, 600)); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 8267b1ccfe265..b23d532cf4e00 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -6,20 +6,20 @@ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_ #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h" -#include "fml/task_runner.h" -#include "impeller/base/thread_safety.h" -#include "third_party/skia/include/core/SkRect.h" #include #include "flutter/flow/surface.h" #include "flutter/fml/memory/weak_ptr.h" +#include "flutter/fml/task_runner.h" #include "flutter/fml/trace_event.h" +#include "flutter/impeller/base/thread_safety.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewResponder.h" -#import "flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.h" -#import "flutter/shell/platform/darwin/ios/ios_context.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" +#include "third_party/skia/include/core/SkRect.h" // A UIView that acts as a clipping mask for the |ChildClippingView|. // @@ -134,8 +134,7 @@ // 2. Dispatching all events that are hittested to the embedded view to the FlutterView. @interface FlutterTouchInterceptingView : UIView - (instancetype)initWithEmbeddedView:(UIView*)embeddedView - platformViewsController: - (fml::WeakPtr)platformViewsController + platformViewsController:(FlutterPlatformViewsController*)platformViewsController gestureRecognizersBlockingPolicy: (FlutterPlatformViewGestureRecognizersBlockingPolicy)blockingPolicy; @@ -192,8 +191,7 @@ // directly to the FlutterView. @interface ForwardingGestureRecognizer : UIGestureRecognizer - (instancetype)initWithTarget:(id)target - platformViewsController: - (fml::WeakPtr)platformViewsController; + platformViewsController:(FlutterPlatformViewsController*)platformViewsController; - (ForwardingGestureRecognizer*)recreateRecognizerWithTarget:(id)target; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h b/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h index 28b9b5636296b..e5f2f6343b843 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h @@ -18,10 +18,30 @@ NS_ASSUME_NONNULL_BEGIN * sends all of selector calls from accessibility services to the * owner SemanticsObject. */ -@interface FlutterSemanticsScrollView : UIScrollView +@interface FlutterSemanticsScrollView : UIScrollView @property(nonatomic, weak, nullable) SemanticsObject* semanticsObject; +/// Whether this scroll view's content offset is actively being updated by UIKit +/// or other the system services. +/// +/// This flag is set by the `FlutterSemanticsScrollView` itself, typically in +/// one of the `UIScrollViewDelegate` methods. +/// +/// When this flag is true, the `SemanticsObject` implementation ignores all +/// content offset updates coming from the Flutter framework, to prevent +/// potential feedback loops (especially when the framework is only echoing +/// the new content offset back to this scroll view). +/// +/// For example, to scroll a scrollable container with iOS full keyboard access, +/// the iOS focus system uses a display link to scroll the container to the +/// desired offset animatedly. If the user changes the scroll offset during the +/// animation, the display link will be invalidated and the scrolling animation +/// will be interrupted. For simplicity, content offset updates coming from the +/// framework will be ignored in the relatively short animation duration (~1s), +/// allowing the scrolling animation to finish. +@property(nonatomic, readonly) BOOL isDoingSystemScrolling; + - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)coder NS_UNAVAILABLE; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm b/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm index 9b74e2ddabc79..c6952c72b71ec 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm @@ -15,6 +15,8 @@ - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject { self = [super initWithFrame:CGRectZero]; if (self) { _semanticsObject = semanticsObject; + _isDoingSystemScrolling = NO; + self.delegate = self; } return self; } @@ -105,4 +107,14 @@ - (NSInteger)accessibilityElementCount { return self.semanticsObject.children.count; } +- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView + withVelocity:(CGPoint)velocity + targetContentOffset:(inout CGPoint*)targetContentOffset { + _isDoingSystemScrolling = YES; +} + +- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView { + _isDoingSystemScrolling = NO; +} + @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.h b/shell/platform/darwin/ios/framework/Source/FlutterView.h index 53dd50e45d6a8..80619e44b777c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.h @@ -14,12 +14,11 @@ @protocol FlutterViewEngineDelegate @property(nonatomic, readonly) BOOL isUsingImpeller; +@property(nonatomic, readonly) FlutterPlatformViewsController* platformViewsController; - (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type asBase64Encoded:(BOOL)base64Encode; -- (std::shared_ptr&)platformViewsController; - /** * A callback that is called when iOS queries accessibility information of the Flutter view. * diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 319f423d84afa..2fd71c0874b16 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -745,14 +745,14 @@ - (void)surfaceUpdated:(BOOL)appeared { // thread. if (appeared) { [self installFirstFrameCallback]; - [self.engine platformViewsController]->SetFlutterView(self.flutterView); - [self.engine platformViewsController]->SetFlutterViewController(self); + self.platformViewsController.flutterView = self.flutterView; + self.platformViewsController.flutterViewController = self; [self.engine iosPlatformView]->NotifyCreated(); } else { self.displayingFlutterUI = NO; [self.engine iosPlatformView]->NotifyDestroyed(); - [self.engine platformViewsController]->SetFlutterView(nullptr); - [self.engine platformViewsController]->SetFlutterViewController(nullptr); + self.platformViewsController.flutterView = nil; + self.platformViewsController.flutterViewController = nil; } } @@ -2321,7 +2321,7 @@ - (BOOL)prefersStatusBarHidden { #pragma mark - Platform views -- (std::shared_ptr&)platformViewsController { +- (FlutterPlatformViewsController*)platformViewsController { return self.engine.platformViewsController; } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h index 62a7df4133a1d..3645d2c376f65 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h @@ -5,11 +5,12 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ -#include "flutter/fml/time/time_point.h" - #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" + +#include "flutter/fml/time/time_point.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterKeySecondaryResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewResponder.h" @@ -56,7 +57,8 @@ typedef void (^FlutterKeyboardAnimationCallback)(fml::TimePoint); */ @property(nonatomic, assign, readwrite) BOOL prefersStatusBarHidden; -- (std::shared_ptr&)platformViewsController; +@property(nonatomic, readonly) FlutterPlatformViewsController* platformViewsController; + - (FlutterRestorationPlugin*)restorationPlugin; // Accepts keypress events, and then calls |nextAction| if the event was not diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewTest.mm index 08cf885da5e2a..357c65e4c8e0f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewTest.mm @@ -13,13 +13,12 @@ @interface FakeDelegate : NSObject @property(nonatomic, assign) BOOL isUsingImpeller; @end -@implementation FakeDelegate { - std::shared_ptr _platformViewsController; -} +@implementation FakeDelegate + +@synthesize platformViewsController = _platformViewsController; - (instancetype)init { _callbackCalled = NO; - _platformViewsController = std::shared_ptr(nullptr); return self; } @@ -28,10 +27,6 @@ - (instancetype)init { return {}; } -- (std::shared_ptr&)platformViewsController { - return _platformViewsController; -} - - (void)flutterViewAccessibilityDidCall { _callbackCalled = YES; } diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm b/shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm index 3448b9280536b..c3262de538dab 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm @@ -3,7 +3,10 @@ // found in the LICENSE file. #import "SemanticsObject.h" +#include "flutter/lib/ui/semantics/semantics_node.h" +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h" FLUTTER_ASSERT_ARC @@ -27,10 +30,19 @@ // translated to calls such as -[NSObject accessibilityActivate]), while most // other key events are dispatched to the framework. @interface SemanticsObject (UIFocusSystem) +/// The `UIFocusItem` that represents this SemanticsObject. +/// +/// For regular `SemanticsObject`s, this method returns `self`, +/// for `FlutterScrollableSemanticsObject`s, this method returns its scroll view. +- (id)focusItem; @end @implementation SemanticsObject (UIFocusSystem) +- (id)focusItem { + return self; +} + #pragma mark - UIFocusEnvironment Conformance - (void)setNeedsFocusUpdate { @@ -49,7 +61,7 @@ - (void)didUpdateFocusInContext:(UIFocusUpdateContext*)context - (id)parentFocusEnvironment { // The root SemanticsObject node's parent is the FlutterView. - return self.parent ?: self.bridge->view(); + return self.parent.focusItem ?: self.bridge->view(); } - (NSArray>*)preferredFocusEnvironments { @@ -71,8 +83,57 @@ - (BOOL)canBecomeFocused { return self.node.HasAction(flutter::SemanticsAction::kTap); } +// The frame is described in the `coordinateSpace` of the +// `parentFocusEnvironment` (all `parentFocusEnvironment`s are `UIFocusItem`s). +// +// See also the `coordinateSpace` implementation. +// TODO(LongCatIsLooong): use CoreGraphics types. - (CGRect)frame { - return self.accessibilityFrame; + SkPoint quad[4] = {SkPoint::Make(self.node.rect.left(), self.node.rect.top()), + SkPoint::Make(self.node.rect.left(), self.node.rect.bottom()), + SkPoint::Make(self.node.rect.right(), self.node.rect.top()), + SkPoint::Make(self.node.rect.right(), self.node.rect.bottom())}; + + SkM44 transform = self.node.transform; + FlutterSemanticsScrollView* scrollView; + for (SemanticsObject* ancestor = self.parent; ancestor; ancestor = ancestor.parent) { + if ([ancestor isKindOfClass:[FlutterScrollableSemanticsObject class]]) { + scrollView = ((FlutterScrollableSemanticsObject*)ancestor).scrollView; + break; + } + transform = ancestor.node.transform * transform; + } + + for (auto& vertex : quad) { + SkV4 vector = transform.map(vertex.x(), vertex.y(), 0, 1); + vertex = SkPoint::Make(vector.x / vector.w, vector.y / vector.w); + } + + SkRect rect; + rect.setBounds(quad, 4); + // If this UIFocusItemContainer's coordinateSpace is a UIScrollView, offset + // the rect by `contentOffset` because the contentOffset translation is + // incorporated into the paint transform at different node depth in UIKit + // and Flutter. In Flutter, the translation is added to the cells + // while in UIKit the viewport's bounds is manipulated (IOW, each cell's frame + // in the UIScrollView coordinateSpace does not change when the UIScrollView + // scrolls). + CGRect unscaledRect = + CGRectMake(rect.x() + scrollView.bounds.origin.x, rect.y() + scrollView.bounds.origin.y, + rect.width(), rect.height()); + if (scrollView) { + return unscaledRect; + } + // `rect` could be in physical pixels since the root RenderObject ("RenderView") + // applies a transform that turns logical pixels to physical pixels. Undo the + // transform by dividing the coordinates by the screen's scale factor, if this + // UIFocusItem's reported `coordinateSpace` is the root view (which means this + // UIFocusItem is not inside of a scroll view). + // + // Screen can be nil if the FlutterView is covered by another native view. + CGFloat scale = (self.bridge->view().window.screen ?: UIScreen.mainScreen).scale; + return CGRectMake(unscaledRect.origin.x / scale, unscaledRect.origin.y / scale, + unscaledRect.size.width / scale, unscaledRect.size.height / scale); } #pragma mark - UIFocusItemContainer Conformance @@ -87,16 +148,94 @@ - (CGRect)frame { // // This method is only supposed to return items within the given // rect but returning everything in the subtree seems to work fine. - NSMutableArray* reversedItems = + NSMutableArray>* reversedItems = [[NSMutableArray alloc] initWithCapacity:self.childrenInHitTestOrder.count]; for (NSUInteger i = 0; i < self.childrenInHitTestOrder.count; ++i) { - [reversedItems - addObject:self.childrenInHitTestOrder[self.childrenInHitTestOrder.count - 1 - i]]; + SemanticsObject* child = self.childrenInHitTestOrder[self.childrenInHitTestOrder.count - 1 - i]; + [reversedItems addObject:child.focusItem]; } return reversedItems; } - (id)coordinateSpace { - return self.bridge->view(); + // A regular SemanticsObject uses the same coordinate space as its parent. + return self.parent.coordinateSpace ?: self.bridge->view(); +} + +@end + +/// Scrollable containers interact with the iOS focus engine using the +/// `UIFocusItemScrollableContainer` protocol. The said protocol (and other focus-related protocols) +/// does not provide means to inform the focus system of layout changes. In order for the focus +/// highlight to update properly as the scroll view scrolls, this implementation incorporates a +/// UIScrollView into the focus hierarchy to workaround the highlight update problem. +/// +/// As a result, in the current implementation only scrollable containers and the root node +/// establish their own `coordinateSpace`s. All other `UIFocusItemContainter`s use the same +/// `coordinateSpace` as the containing UIScrollView, or the root `FlutterView`, whichever is +/// closer. +/// +/// See also the `frame` method implementation. +#pragma mark - Scrolling + +@interface FlutterScrollableSemanticsObject (CoordinateSpace) +@end + +@implementation FlutterScrollableSemanticsObject (CoordinateSpace) +- (id)coordinateSpace { + // A scrollable SemanticsObject uses the same coordinate space as the scroll view. + // This may not work very well in nested scroll views. + return self.scrollView; +} + +- (id)focusItem { + return self.scrollView; +} + +@end + +@interface FlutterSemanticsScrollView (UIFocusItemScrollableContainer) < + UIFocusItemScrollableContainer> +@end + +@implementation FlutterSemanticsScrollView (UIFocusItemScrollableContainer) + +#pragma mark - FlutterSemanticsScrollView UIFocusItemScrollableContainer Conformance + +- (CGSize)visibleSize { + return self.frame.size; +} + +- (void)setContentOffset:(CGPoint)contentOffset { + [super setContentOffset:contentOffset]; + // Do no send flutter::SemanticsAction::kScrollToOffset if it's triggered + // by a framework update. + if (![self.semanticsObject isAccessibilityBridgeAlive] || !self.isDoingSystemScrolling) { + return; + } + + double offset[2] = {contentOffset.x, contentOffset.y}; + FlutterStandardTypedData* offsetData = [FlutterStandardTypedData + typedDataWithFloat64:[NSData dataWithBytes:&offset length:sizeof(offset)]]; + NSData* encoded = [[FlutterStandardMessageCodec sharedInstance] encode:offsetData]; + self.semanticsObject.bridge->DispatchSemanticsAction( + self.semanticsObject.uid, flutter::SemanticsAction::kScrollToOffset, + fml::MallocMapping::Copy(encoded.bytes, encoded.length)); +} + +- (BOOL)canBecomeFocused { + return NO; +} + +- (id)parentFocusEnvironment { + return self.semanticsObject.parentFocusEnvironment; +} + +- (NSArray>*)preferredFocusEnvironments { + return nil; +} + +- (NSArray>*)focusItemsInRect:(CGRect)rect { + return [self.semanticsObject focusItemsInRect:rect]; } @end diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObject.h b/shell/platform/darwin/ios/framework/Source/SemanticsObject.h index d3441ec0058b1..2c9e0516112ea 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObject.h +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObject.h @@ -10,6 +10,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/lib/ui/semantics/semantics_node.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h" constexpr int32_t kRootNodeId = 0; @@ -186,7 +187,7 @@ constexpr float kScrollExtentMaxForInf = 1000; /// The semantics object for scrollable. This class creates an UIScrollView to interact with the /// iOS. @interface FlutterScrollableSemanticsObject : SemanticsObject - +@property(nonatomic, readonly) FlutterSemanticsScrollView* scrollView; @end /** diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm b/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm index 8212c2fd01f72..39882196e8e99 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm @@ -154,6 +154,8 @@ - (instancetype)initWithBridge:(fml::WeakPtr)br _scrollView = [[FlutterSemanticsScrollView alloc] initWithSemanticsObject:self]; [_scrollView setShowsHorizontalScrollIndicator:NO]; [_scrollView setShowsVerticalScrollIndicator:NO]; + [_scrollView setContentInset:UIEdgeInsetsZero]; + [_scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; [self.bridge->view() addSubview:_scrollView]; } return self; @@ -174,7 +176,10 @@ - (void)accessibilityBridgeDidFinishUpdate { // contentOffset is 0.0, only the scroll down action is available. self.scrollView.frame = self.accessibilityFrame; self.scrollView.contentSize = [self contentSizeInternal]; - [self.scrollView setContentOffset:[self contentOffsetInternal] animated:NO]; + // See the documentation on `isDoingSystemScrolling`. + if (!self.scrollView.isDoingSystemScrolling) { + [self.scrollView setContentOffset:self.contentOffsetInternal animated:NO]; + } } - (id)nativeAccessibility { diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm b/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm index ff514b6730057..02fb11f98336c 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm @@ -7,6 +7,7 @@ #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h" #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h" #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h" @@ -19,6 +20,10 @@ @interface SemanticsObject (UIFocusSystem) @end +@interface FlutterScrollableSemanticsObject (UIFocusItemScrollableContainer) < + UIFocusItemScrollableContainer> +@end + @interface TextInputSemanticsObject (Test) - (UIView*)textInputSurrogate; @end @@ -665,7 +670,7 @@ - (void)testFlutterScrollableSemanticsObjectReturnsParentContainerIfNoChildren { XCTAssertEqual(container.semanticsObject, parentObject); } -- (void)testFlutterScrollableSemanticsObjectHidesScrollBar { +- (void)testFlutterScrollableSemanticsObjectNoScrollBarOrContentInsets { fml::WeakPtrFactory factory( new flutter::testing::MockAccessibilityBridge()); fml::WeakPtr bridge = factory.GetWeakPtr(); @@ -685,6 +690,9 @@ - (void)testFlutterScrollableSemanticsObjectHidesScrollBar { XCTAssertFalse(scrollView.showsHorizontalScrollIndicator); XCTAssertFalse(scrollView.showsVerticalScrollIndicator); + XCTAssertEqual(scrollView.contentInsetAdjustmentBehavior, + UIScrollViewContentInsetAdjustmentNever); + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.contentInset, UIEdgeInsetsZero)); } - (void)testSemanticsObjectBuildsAttributedString { @@ -1155,6 +1163,19 @@ - (void)testTextInputSemanticsObject_editActions { [self waitForExpectationsWithTimeout:1 handler:nil]; } +- (void)testSliderSemanticsObject { + fml::WeakPtrFactory factory( + new flutter::testing::MockAccessibilityBridge()); + fml::WeakPtr bridge = factory.GetWeakPtr(); + + flutter::SemanticsNode node; + node.flags = static_cast(flutter::SemanticsFlags::kIsSlider); + SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0]; + [object setSemanticsNode:&node]; + [object accessibilityBridgeDidFinishUpdate]; + XCTAssertEqual([object accessibilityActivate], YES); +} + - (void)testUIFocusItemConformance { fml::WeakPtrFactory factory( new flutter::testing::MockAccessibilityBridge()); @@ -1207,17 +1228,57 @@ - (void)testUIFocusItemContainerConformance { XCTAssertTrue([itemsInRect containsObject:child2]); } -- (void)testSliderSemanticsObject { +- (void)testUIFocusItemScrollableContainerConformance { fml::WeakPtrFactory factory( new flutter::testing::MockAccessibilityBridge()); - fml::WeakPtr bridge = factory.GetWeakPtr(); + fml::WeakPtr bridge = factory.GetWeakPtr(); + FlutterScrollableSemanticsObject* scrollable = + [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:5]; + + // setContentOffset + CGPoint p = CGPointMake(123.0, 456.0); + [scrollable.scrollView scrollViewWillEndDragging:scrollable.scrollView + withVelocity:CGPointZero + targetContentOffset:&p]; + scrollable.scrollView.contentOffset = p; + [scrollable.scrollView scrollViewDidEndDecelerating:scrollable.scrollView]; + XCTAssertEqual(bridge->observations.size(), (size_t)1); + XCTAssertEqual(bridge->observations[0].id, 5); + XCTAssertEqual(bridge->observations[0].action, flutter::SemanticsAction::kScrollToOffset); + + std::vector args = bridge->observations[0].args; + XCTAssertEqual(args.size(), 3 * sizeof(CGFloat)); + + NSData* encoded = [NSData dataWithBytes:args.data() length:args.size()]; + FlutterStandardTypedData* decoded = [[FlutterStandardMessageCodec sharedInstance] decode:encoded]; + CGPoint point = CGPointZero; + memcpy(&point, decoded.data.bytes, decoded.data.length); + XCTAssertTrue(CGPointEqualToPoint(point, p)); +} +- (void)testUIFocusItemScrollableContainerNoFeedbackLoops { + fml::WeakPtrFactory factory( + new flutter::testing::MockAccessibilityBridge()); + fml::WeakPtr bridge = factory.GetWeakPtr(); + FlutterScrollableSemanticsObject* scrollable = + [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:5]; + + // setContentOffset + const CGPoint p = CGPointMake(0.0, 456.0); + scrollable.scrollView.contentOffset = p; + bridge->observations.clear(); + + const SkScalar scrollPosition = p.y + 0.0000000000000001; flutter::SemanticsNode node; - node.flags = static_cast(flutter::SemanticsFlags::kIsSlider); - SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0]; - [object setSemanticsNode:&node]; - [object accessibilityBridgeDidFinishUpdate]; - XCTAssertEqual([object accessibilityActivate], YES); -} + node.flags = static_cast(flutter::SemanticsFlags::kHasImplicitScrolling); + node.actions = flutter::kVerticalScrollSemanticsActions; + node.rect = SkRect::MakeXYWH(0, 0, 100, 200); + node.scrollExtentMax = 10000; + node.scrollPosition = scrollPosition; + node.transform = {1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, scrollPosition, 0, 1.0}; + [scrollable setSemanticsNode:&node]; + [scrollable accessibilityBridgeDidFinishUpdate]; + XCTAssertEqual(bridge->observations.size(), (size_t)0); +} @end diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h b/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h index 4ccd57b1bbf6b..a740349ab1376 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h @@ -15,10 +15,18 @@ namespace testing { class SemanticsActionObservation { public: SemanticsActionObservation(int32_t observed_id, SemanticsAction observed_action) - : id(observed_id), action(observed_action) {} + : id(observed_id), action(observed_action), args({}) {} + + SemanticsActionObservation(int32_t observed_id, + SemanticsAction observed_action, + fml::MallocMapping& args) + : id(observed_id), + action(observed_action), + args(args.GetMapping(), args.GetMapping() + args.GetSize()) {} int32_t id; SemanticsAction action; + std::vector args; }; class MockAccessibilityBridge : public AccessibilityBridgeIos { @@ -38,14 +46,12 @@ class MockAccessibilityBridge : public AccessibilityBridgeIos { void DispatchSemanticsAction(int32_t id, SemanticsAction action, fml::MallocMapping args) override { - SemanticsActionObservation observation(id, action); + SemanticsActionObservation observation(id, action, args); observations.push_back(observation); } void AccessibilityObjectDidBecomeFocused(int32_t id) override {} void AccessibilityObjectDidLoseFocus(int32_t id) override {} - std::shared_ptr GetPlatformViewsController() const override { - return nil; - } + FlutterPlatformViewsController* GetPlatformViewsController() const override { return nil; } std::vector observations; bool isVoiceOverRunningValue; @@ -69,14 +75,12 @@ class MockAccessibilityBridgeNoWindow : public AccessibilityBridgeIos { void DispatchSemanticsAction(int32_t id, SemanticsAction action, fml::MallocMapping args) override { - SemanticsActionObservation observation(id, action); + SemanticsActionObservation observation(id, action, args); observations.push_back(observation); } void AccessibilityObjectDidBecomeFocused(int32_t id) override {} void AccessibilityObjectDidLoseFocus(int32_t id) override {} - std::shared_ptr GetPlatformViewsController() const override { - return nil; - } + FlutterPlatformViewsController* GetPlatformViewsController() const override { return nil; } std::vector observations; bool isVoiceOverRunningValue; diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h index ffbd8e49dddf7..e808b88d20f8a 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h @@ -50,7 +50,7 @@ class AccessibilityBridge final : public AccessibilityBridgeIos { AccessibilityBridge(FlutterViewController* view_controller, PlatformViewIOS* platform_view, - std::shared_ptr platform_views_controller, + __weak FlutterPlatformViewsController* platform_views_controller, std::unique_ptr ios_delegate = nullptr); ~AccessibilityBridge(); @@ -72,7 +72,7 @@ class AccessibilityBridge final : public AccessibilityBridgeIos { fml::WeakPtr GetWeakPtr(); - std::shared_ptr GetPlatformViewsController() const override { + FlutterPlatformViewsController* GetPlatformViewsController() const override { return platform_views_controller_; }; @@ -91,7 +91,7 @@ class AccessibilityBridge final : public AccessibilityBridgeIos { FlutterViewController* view_controller_; PlatformViewIOS* platform_view_; - const std::shared_ptr platform_views_controller_; + __weak FlutterPlatformViewsController* platform_views_controller_; // If the this id is kSemanticObjectIdInvalid, it means either nothing has // been focused or the focus is currently outside of the flutter application // (i.e. the status bar or keyboard) diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index 62467d3406f43..daf6389834c81 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -42,11 +42,11 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification, AccessibilityBridge::AccessibilityBridge( FlutterViewController* view_controller, PlatformViewIOS* platform_view, - std::shared_ptr platform_views_controller, + __weak FlutterPlatformViewsController* platform_views_controller, std::unique_ptr ios_delegate) : view_controller_(view_controller), platform_view_(platform_view), - platform_views_controller_(std::move(platform_views_controller)), + platform_views_controller_(platform_views_controller), last_focused_semantics_object_id_(kSemanticObjectIdInvalid), objects_([[NSMutableDictionary alloc] init]), previous_routes_({}), @@ -271,11 +271,13 @@ static void ReplaceSemanticsObject(SemanticsObject* oldObject, } else if (node.HasFlag(flutter::SemanticsFlags::kHasImplicitScrolling)) { return [[FlutterScrollableSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id]; } else if (node.IsPlatformViewNode()) { - return [[FlutterPlatformViewSemanticsContainer alloc] - initWithBridge:weak_ptr - uid:node.id - platformView:weak_ptr->GetPlatformViewsController()->GetFlutterTouchInterceptingViewByID( - node.platformViewId)]; + FlutterPlatformViewsController* platformViewsController = + weak_ptr->GetPlatformViewsController(); + FlutterTouchInterceptingView* touchInterceptingView = + [platformViewsController flutterTouchInterceptingViewForId:node.platformViewId]; + return [[FlutterPlatformViewSemanticsContainer alloc] initWithBridge:weak_ptr + uid:node.id + platformView:touchInterceptingView]; } else { return [[FlutterSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id]; } diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h index 0da3646a2e802..2168ca050d072 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h @@ -12,9 +12,9 @@ #include "flutter/lib/ui/semantics/semantics_node.h" @class UIView; +@class FlutterPlatformViewsController; namespace flutter { -class PlatformViewsController; /// Interface that represents an accessibility bridge for iOS. class AccessibilityBridgeIos { @@ -39,7 +39,7 @@ class AccessibilityBridgeIos { * The input id is the uid of the newly focused SemanticObject. */ virtual void AccessibilityObjectDidLoseFocus(int32_t id) = 0; - virtual std::shared_ptr GetPlatformViewsController() const = 0; + virtual FlutterPlatformViewsController* GetPlatformViewsController() const = 0; }; } // namespace flutter diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm index 63c2b14794bf9..343ed99eae983 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm @@ -279,8 +279,9 @@ - (void)testSemanticsDeallocated { /*ui=*/thread_task_runner, /*io=*/thread_task_runner); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(thread_task_runner); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = thread_task_runner; auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -294,19 +295,22 @@ - (void)testSemanticsDeallocated { id mockFlutterViewController = OCMClassMock([FlutterViewController class]); OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView); std::string label = "some label"; - flutterPlatformViewsController->SetFlutterView(mockFlutterView); + flutterPlatformViewsController.flutterView = mockFlutterView; MockFlutterPlatformFactory* factory = [[MockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; auto bridge = std::make_unique( /*view_controller=*/mockFlutterViewController, @@ -322,7 +326,7 @@ - (void)testSemanticsDeallocated { flutter::CustomAccessibilityActionUpdates actions; bridge->UpdateSemantics(/*nodes=*/nodes, /*actions=*/actions); XCTAssertNotNil(gMockPlatformView); - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; } XCTAssertNil(gMockPlatformView); } @@ -340,8 +344,9 @@ - (void)testSemanticsDeallocatedWithoutLoadingView { /*ui=*/thread_task_runner, /*io=*/thread_task_runner); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(thread_task_runner); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = thread_task_runner; auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -353,16 +358,19 @@ - (void)testSemanticsDeallocatedWithoutLoadingView { /*is_gpu_disabled_sync_switch=*/std::make_shared()); MockFlutterPlatformFactory* factory = [[MockFlutterPlatformFactory alloc] init]; - flutterPlatformViewsController->RegisterViewFactory( - factory, @"MockFlutterPlatformView", - FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + [flutterPlatformViewsController + registerViewFactory:factory + withId:@"MockFlutterPlatformView" + gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager]; FlutterResult result = ^(id result) { }; - flutterPlatformViewsController->OnMethodCall( - [FlutterMethodCall - methodCallWithMethodName:@"create" - arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); + [flutterPlatformViewsController + onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create" + arguments:@{ + @"id" : @2, + @"viewType" : @"MockFlutterPlatformView" + }] + result:result]; auto bridge = std::make_unique( /*view_controller=*/flutterViewController, @@ -370,7 +378,7 @@ - (void)testSemanticsDeallocatedWithoutLoadingView { /*platform_views_controller=*/flutterPlatformViewsController); XCTAssertNotNil(gMockPlatformView); - flutterPlatformViewsController->Reset(); + [flutterPlatformViewsController reset]; platform_view->NotifyDestroyed(); } XCTAssertNil(gMockPlatformView); @@ -387,8 +395,9 @@ - (void)testReplacedSemanticsDoesNotCleanupChildren { /*ui=*/thread_task_runner, /*io=*/thread_task_runner); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(thread_task_runner); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = thread_task_runner; auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -484,8 +493,9 @@ - (void)testScrollableSemanticsDeallocated { /*ui=*/thread_task_runner, /*io=*/thread_task_runner); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(thread_task_runner); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = thread_task_runner; auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -559,8 +569,8 @@ - (void)testBridgeReplacesSemanticsNode { /*ui=*/thread_task_runner, /*io=*/thread_task_runner); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(thread_task_runner); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; auto platform_view = std::make_unique( /*delegate=*/mock_delegate, /*rendering_api=*/mock_delegate.settings_.enable_impeller @@ -2175,11 +2185,12 @@ - (void)testPlatformViewDestructorDoesNotCallSemanticsAPIs { /*is_gpu_disabled_sync_switch=*/std::make_shared()); id mockFlutterViewController = OCMClassMock([FlutterViewController class]); - auto flutterPlatformViewsController = std::make_shared(); - flutterPlatformViewsController->SetTaskRunner(thread_task_runner); + FlutterPlatformViewsController* flutterPlatformViewsController = + [[FlutterPlatformViewsController alloc] init]; + flutterPlatformViewsController.taskRunner = thread_task_runner; OCMStub([mockFlutterViewController platformViewsController]) - .andReturn(flutterPlatformViewsController.get()); + .andReturn(flutterPlatformViewsController); platform_view->SetOwnerViewController(mockFlutterViewController); platform_view->SetSemanticsEnabled(true); diff --git a/shell/platform/darwin/ios/framework/Source/platform_views_controller.h b/shell/platform/darwin/ios/framework/Source/platform_views_controller.h deleted file mode 100644 index 056586d429456..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/platform_views_controller.h +++ /dev/null @@ -1,325 +0,0 @@ -// 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_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_VIEWS_CONTROLLER_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_VIEWS_CONTROLLER_H_ - -#include -#include -#include - -#include "flutter/flow/surface.h" -#include "flutter/fml/memory/weak_ptr.h" -#include "flutter/fml/task_runner.h" -#include "flutter/fml/trace_event.h" -#include "impeller/base/thread_safety.h" -#include "third_party/skia/include/core/SkRect.h" - -#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h" -#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h" -#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h" -#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewResponder.h" -#import "flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_pool.h" -#import "flutter/shell/platform/darwin/ios/ios_context.h" - -@class FlutterTouchInterceptingView; -@class FlutterClippingMaskViewPool; - -namespace flutter { - -/// @brief Composites Flutter UI and overlay layers alongside embedded UIViews. -class PlatformViewsController { - public: - PlatformViewsController(); - - ~PlatformViewsController() = default; - - /// @brief Retrieve a weak pointer to this controller. - fml::WeakPtr GetWeakPtr(); - - /// @brief Set the platform task runner used to post rendering tasks. - void SetTaskRunner(const fml::RefPtr& platform_task_runner); - - /// @brief Set the flutter view. - void SetFlutterView(UIView* flutter_view) __attribute__((cf_audited_transfer)); - - /// @brief Set the flutter view controller. - void SetFlutterViewController(UIViewController* flutter_view_controller) - __attribute__((cf_audited_transfer)); - - /// @brief Retrieve the view controller. - UIViewController* GetFlutterViewController() - __attribute__((cf_audited_transfer)); - - /// @brief set the factory used to construct embedded UI Views. - void RegisterViewFactory( - NSObject* factory, - NSString* factoryId, - FlutterPlatformViewGestureRecognizersBlockingPolicy gestureRecognizerBlockingPolicy) - __attribute__((cf_audited_transfer)); - - /// @brief Mark the beginning of a frame and record the size of the onscreen. - void BeginFrame(SkISize frame_size); - - /// @brief Cancel the current frame, indicating that no platform views are composited. - /// - /// Additionally, reverts the composition order to its original state at the beginning of the - /// frame. - void CancelFrame(); - - /// @brief Record a platform view in the layer tree to be rendered, along with the positioning and - /// mutator parameters. - /// - /// Called from the raster thread. - void PrerollCompositeEmbeddedView(int64_t view_id, - std::unique_ptr params); - - /// @brief Returns the`FlutterTouchInterceptingView` with the provided view_id. - /// - /// Returns nil if there is no platform view with the provided id. Called - /// from the platform thread. - FlutterTouchInterceptingView* GetFlutterTouchInterceptingViewByID(int64_t view_id); - - /// @brief Determine if thread merging is required after prerolling platform views. - /// - /// Called from the raster thread. - PostPrerollResult PostPrerollAction( - const fml::RefPtr& raster_thread_merger, - bool impeller_enabled); - - /// @brief Mark the end of a compositor frame. - /// - /// May determine changes are required to the thread merging state. - /// Called from the raster thread. - void EndFrame(bool should_resubmit_frame, - const fml::RefPtr& raster_thread_merger, - bool impeller_enabled); - - /// @brief Returns the Canvas for the overlay slice for the given platform view. - /// - /// Called from the raster thread. - DlCanvas* CompositeEmbeddedView(int64_t view_id); - - /// @brief Discards all platform views instances and auxiliary resources. - /// - /// Called from the raster thread. - void Reset(); - - /// @brief Encode rendering for the Flutter overlay views and queue up perform platform view - /// mutations. - /// - /// Called from the raster thread. - bool SubmitFrame(GrDirectContext* gr_context, - const std::shared_ptr& ios_context, - std::unique_ptr frame); - - /// @brief Handler for platform view message channels. - void OnMethodCall(FlutterMethodCall* call, FlutterResult result) - __attribute__((cf_audited_transfer)); - - /// @brief Returns the platform view id if the platform view (or any of its descendant view) is - /// the first responder. - /// - /// Returns -1 if no such platform view is found. - long FindFirstResponderPlatformViewId(); - - /// @brief Pushes backdrop filter mutation to the mutator stack of each visited platform view. - void PushFilterToVisitedPlatformViews(const std::shared_ptr& filter, - const SkRect& filter_rect); - - /// @brief Pushes the view id of a visted platform view to the list of visied platform views. - void PushVisitedPlatformView(int64_t view_id) { visited_platform_views_.push_back(view_id); } - - // visible for testing. - size_t EmbeddedViewCount() const; - - // visible for testing. - size_t LayerPoolSize() const; - - // visible for testing. - // Returns the `FlutterPlatformView`'s `view` object associated with the view_id. - // - // If the `PlatformViewsController` does not contain any `FlutterPlatformView` object or - // a `FlutterPlatformView` object associated with the view_id cannot be found, the method - // returns nil. - UIView* GetPlatformViewByID(int64_t view_id); - - // Visible for testing. - void CompositeWithParams(int64_t view_id, const EmbeddedViewParams& params); - - // Visible for testing. - const EmbeddedViewParams& GetCompositionParams(int64_t view_id) const { - return current_composition_params_.find(view_id)->second; - } - - private: - PlatformViewsController(const PlatformViewsController&) = delete; - PlatformViewsController& operator=(const PlatformViewsController&) = delete; - - struct LayerData { - SkRect rect; - int64_t view_id; - int64_t overlay_id; - std::shared_ptr layer; - }; - - using LayersMap = std::unordered_map; - - // Update the buffers and mutate the platform views in CATransaction. - // - // Runs on the platform thread. - void PerformSubmit(const LayersMap& platform_view_layers, - std::unordered_map& current_composition_params, - const std::unordered_set& views_to_recomposite, - const std::vector& composition_order, - const std::vector>& unused_layers, - const std::vector>& surface_frames); - - /// @brief Populate any missing overlay layers. - /// - /// This requires posting a task to the platform thread and blocking on its completion. - void CreateMissingOverlays(GrDirectContext* gr_context, - const std::shared_ptr& ios_context, - size_t required_overlay_layers); - - void OnCreate(FlutterMethodCall* call, FlutterResult result) __attribute__((cf_audited_transfer)); - - void OnDispose(FlutterMethodCall* call, FlutterResult result) - __attribute__((cf_audited_transfer)); - - void OnAcceptGesture(FlutterMethodCall* call, FlutterResult result) - __attribute__((cf_audited_transfer)); - - void OnRejectGesture(FlutterMethodCall* call, FlutterResult result) - __attribute__((cf_audited_transfer)); - - /// @brief Return all views to be disposed on the platform thread. - std::vector GetViewsToDispose(); - - void ClipViewSetMaskView(UIView* clipView) __attribute__((cf_audited_transfer)); - - // Applies the mutators in the mutators_stack to the UIView chain that was constructed by - // `ReconstructClipViewsChain` - // - // Clips are applied to the `embedded_view`'s super view(|ChildClippingView|) using a - // |FlutterClippingMaskView|. Transforms are applied to `embedded_view` - // - // The `bounding_rect` is the final bounding rect of the PlatformView - // (EmbeddedViewParams::finalBoundingRect). If a clip mutator's rect contains the final bounding - // rect of the PlatformView, the clip mutator is not applied for performance optimization. - void ApplyMutators(const MutatorsStack& mutators_stack, - UIView* embedded_view, - const SkRect& bounding_rect) __attribute__((cf_audited_transfer)); - - std::shared_ptr GetExistingLayer(); - - // Runs on the platform thread. - void CreateLayer(GrDirectContext* gr_context, - const std::shared_ptr& ios_context, - MTLPixelFormat pixel_format); - - // Removes overlay views and platform views that aren't needed in the current frame. - // Must run on the platform thread. - void RemoveUnusedLayers(const std::vector>& unused_layers, - const std::vector& composition_order); - - // Appends the overlay views and platform view and sets their z index based on the composition - // order. - void BringLayersIntoView(const LayersMap& layer_map, - const std::vector& composition_order); - - // Resets the state of the frame. - void ResetFrameState(); - - // The pool of reusable view layers. The pool allows to recycle layer in each frame. - std::unique_ptr layer_pool_; - - // The platform view's |EmbedderViewSlice| keyed off the view id, which contains any subsequent - // operation until the next platform view or the end of the last leaf node in the layer tree. - // - // The Slices are deleted by the PlatformViewsController.reset(). - std::unordered_map> slices_; - - UIView* flutter_view_; - UIViewController* flutter_view_controller_; - FlutterClippingMaskViewPool* mask_view_pool_; - std::unordered_map*> factories_; - - // The FlutterPlatformViewGestureRecognizersBlockingPolicy for each type of platform view. - std::unordered_map - gesture_recognizers_blocking_policies_; - - /// The size of the current onscreen surface in physical pixels. - SkISize frame_size_; - - /// The task runner for posting tasks to the platform thread. - fml::RefPtr platform_task_runner_; - - /// Each of the following structs stores part of the platform view hierarchy according to its - /// ID. - /// - /// This data must only be accessed on the platform thread. - struct PlatformViewData { - NSObject* view; - FlutterTouchInterceptingView* touch_interceptor; - UIView* root_view; - }; - - /// This data must only be accessed on the platform thread. - std::unordered_map platform_views_; - - /// The composition parameters for each platform view. - /// - /// This state is only modified on the raster thread. - std::unordered_map current_composition_params_; - - /// Method channel `OnDispose` calls adds the views to be disposed to this set to be disposed on - /// the next frame. - /// - /// This state is modified on both the platform and raster thread. - std::unordered_set views_to_dispose_; - - /// view IDs in composition order. - /// - /// This state is only modified on the raster thread. - std::vector composition_order_; - - /// platform view IDs visited during layer tree composition. - /// - /// This state is only modified on the raster thread. - std::vector visited_platform_views_; - - /// Only composite platform views in this set. - /// - /// This state is only modified on the raster thread. - std::unordered_set views_to_recomposite_; - -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - /// A set to keep track of embedded views that do not have (0, 0) origin. - /// An insertion triggers a warning message about non-zero origin logged on the debug console. - /// See https://github.com/flutter/flutter/issues/109700 for details. - std::unordered_set non_zero_origin_views_; -#endif - - /// @brief The composition order from the previous thread. - /// - /// Only accessed from the platform thread. - std::vector previous_composition_order_; - - /// Whether the previous frame had any platform views in active composition order. - /// - /// This state is tracked so that the first frame after removing the last platform view - /// runs through the platform view rendering code path, giving us a chance to remove the - /// platform view from the UIView hierarchy. - /// - /// Only accessed from the raster thread. - bool had_platform_views_ = false; - - // WeakPtrFactory must be the last member. - std::unique_ptr> weak_factory_; -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_VIEWS_CONTROLLER_H_ diff --git a/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm b/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm deleted file mode 100644 index 819a6b8c12124..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm +++ /dev/null @@ -1,891 +0,0 @@ -// 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. - -#import "shell/platform/darwin/ios/framework/Source/platform_views_controller.h" - -#include "flutter/display_list/effects/image_filters/dl_blur_image_filter.h" -#include "flutter/flow/surface_frame.h" -#include "flutter/flow/view_slicer.h" -#include "flutter/fml/make_copyable.h" -#include "flutter/fml/synchronization/count_down_latch.h" - -#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h" -#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" -#import "flutter/shell/platform/darwin/ios/ios_surface.h" - -namespace { - -// The number of frames the rasterizer task runner will continue -// to run on the platform thread after no platform view is rendered. -// -// Note: this is an arbitrary number. -static const int kDefaultMergedLeaseDuration = 10; - -static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity = 5; - -// Converts a SkMatrix to CATransform3D. -// -// Certain fields are ignored in CATransform3D since SkMatrix is 3x3 and CATransform3D is 4x4. -CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix) { - // Skia only supports 2D transform so we don't map z. - CATransform3D transform = CATransform3DIdentity; - transform.m11 = matrix.getScaleX(); - transform.m21 = matrix.getSkewX(); - transform.m41 = matrix.getTranslateX(); - transform.m14 = matrix.getPerspX(); - - transform.m12 = matrix.getSkewY(); - transform.m22 = matrix.getScaleY(); - transform.m42 = matrix.getTranslateY(); - transform.m24 = matrix.getPerspY(); - return transform; -} - -// Reset the anchor of `layer` to match the transform operation from flow. -// -// The position of the `layer` should be unchanged after resetting the anchor. -void ResetAnchor(CALayer* layer) { - // Flow uses (0, 0) to apply transform matrix so we need to match that in Quartz. - layer.anchorPoint = CGPointZero; - layer.position = CGPointZero; -} - -CGRect GetCGRectFromSkRect(const SkRect& clipSkRect) { - return CGRectMake(clipSkRect.fLeft, clipSkRect.fTop, clipSkRect.fRight - clipSkRect.fLeft, - clipSkRect.fBottom - clipSkRect.fTop); -} - -// Determines if the `clip_rect` from a clipRect mutator contains the -// `platformview_boundingrect`. -// -// `clip_rect` is in its own coordinate space. The rect needs to be transformed by -// `transform_matrix` to be in the coordinate space where the PlatformView is displayed. -// -// `platformview_boundingrect` is the final bounding rect of the PlatformView in the coordinate -// space where the PlatformView is displayed. -bool ClipRectContainsPlatformViewBoundingRect(const SkRect& clip_rect, - const SkRect& platformview_boundingrect, - const SkMatrix& transform_matrix) { - SkRect transformed_rect = transform_matrix.mapRect(clip_rect); - return transformed_rect.contains(platformview_boundingrect); -} - -// Determines if the `clipRRect` from a clipRRect mutator contains the -// `platformview_boundingrect`. -// -// `clip_rrect` is in its own coordinate space. The rrect needs to be transformed by -// `transform_matrix` to be in the coordinate space where the PlatformView is displayed. -// -// `platformview_boundingrect` is the final bounding rect of the PlatformView in the coordinate -// space where the PlatformView is displayed. -bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, - const SkRect& platformview_boundingrect, - const SkMatrix& transform_matrix) { - SkVector upper_left = clip_rrect.radii(SkRRect::Corner::kUpperLeft_Corner); - SkVector upper_right = clip_rrect.radii(SkRRect::Corner::kUpperRight_Corner); - SkVector lower_right = clip_rrect.radii(SkRRect::Corner::kLowerRight_Corner); - SkVector lower_left = clip_rrect.radii(SkRRect::Corner::kLowerLeft_Corner); - SkScalar transformed_upper_left_x = transform_matrix.mapRadius(upper_left.x()); - SkScalar transformed_upper_left_y = transform_matrix.mapRadius(upper_left.y()); - SkScalar transformed_upper_right_x = transform_matrix.mapRadius(upper_right.x()); - SkScalar transformed_upper_right_y = transform_matrix.mapRadius(upper_right.y()); - SkScalar transformed_lower_right_x = transform_matrix.mapRadius(lower_right.x()); - SkScalar transformed_lower_right_y = transform_matrix.mapRadius(lower_right.y()); - SkScalar transformed_lower_left_x = transform_matrix.mapRadius(lower_left.x()); - SkScalar transformed_lower_left_y = transform_matrix.mapRadius(lower_left.y()); - SkRect transformed_clip_rect = transform_matrix.mapRect(clip_rrect.rect()); - SkRRect transformed_rrect; - SkVector corners[] = {{transformed_upper_left_x, transformed_upper_left_y}, - {transformed_upper_right_x, transformed_upper_right_y}, - {transformed_lower_right_x, transformed_lower_right_y}, - {transformed_lower_left_x, transformed_lower_left_y}}; - transformed_rrect.setRectRadii(transformed_clip_rect, corners); - return transformed_rrect.contains(platformview_boundingrect); -} - -} // namespace - -namespace flutter { - -// Becomes NO if Apple's API changes and blurred backdrop filters cannot be applied. -BOOL canApplyBlurBackdrop = YES; - -PlatformViewsController::PlatformViewsController() - : layer_pool_(std::make_unique()), - weak_factory_(std::make_unique>(this)) { - mask_view_pool_ = - [[FlutterClippingMaskViewPool alloc] initWithCapacity:kFlutterClippingMaskViewPoolCapacity]; -}; - -void PlatformViewsController::SetTaskRunner( - const fml::RefPtr& platform_task_runner) { - platform_task_runner_ = platform_task_runner; -} - -fml::WeakPtr PlatformViewsController::GetWeakPtr() { - return weak_factory_->GetWeakPtr(); -} - -void PlatformViewsController::SetFlutterView(UIView* flutter_view) { - flutter_view_ = flutter_view; -} - -void PlatformViewsController::SetFlutterViewController( - UIViewController* flutter_view_controller) { - flutter_view_controller_ = flutter_view_controller; -} - -UIViewController* PlatformViewsController::GetFlutterViewController() { - return flutter_view_controller_; -} - -void PlatformViewsController::OnMethodCall(FlutterMethodCall* call, FlutterResult result) { - if ([[call method] isEqualToString:@"create"]) { - OnCreate(call, result); - } else if ([[call method] isEqualToString:@"dispose"]) { - OnDispose(call, result); - } else if ([[call method] isEqualToString:@"acceptGesture"]) { - OnAcceptGesture(call, result); - } else if ([[call method] isEqualToString:@"rejectGesture"]) { - OnRejectGesture(call, result); - } else { - result(FlutterMethodNotImplemented); - } -} - -void PlatformViewsController::OnCreate(FlutterMethodCall* call, FlutterResult result) { - NSDictionary* args = [call arguments]; - - int64_t viewId = [args[@"id"] longLongValue]; - NSString* viewTypeString = args[@"viewType"]; - std::string viewType(viewTypeString.UTF8String); - - if (platform_views_.count(viewId) != 0) { - result([FlutterError errorWithCode:@"recreating_view" - message:@"trying to create an already created view" - details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); - return; - } - - NSObject* factory = factories_[viewType]; - if (factory == nil) { - result([FlutterError - errorWithCode:@"unregistered_view_type" - message:[NSString stringWithFormat:@"A UIKitView widget is trying to create a " - @"PlatformView with an unregistered type: < %@ >", - viewTypeString] - details:@"If you are the author of the PlatformView, make sure `registerViewFactory` " - @"is invoked.\n" - @"See: " - @"https://docs.flutter.dev/development/platform-integration/" - @"platform-views#on-the-platform-side-1 for more details.\n" - @"If you are not the author of the PlatformView, make sure to call " - @"`GeneratedPluginRegistrant.register`."]); - return; - } - - id params = nil; - if ([factory respondsToSelector:@selector(createArgsCodec)]) { - NSObject* codec = [factory createArgsCodec]; - if (codec != nil && args[@"params"] != nil) { - FlutterStandardTypedData* paramsData = args[@"params"]; - params = [codec decode:paramsData.data]; - } - } - - NSObject* embedded_view = [factory createWithFrame:CGRectZero - viewIdentifier:viewId - arguments:params]; - UIView* platform_view = [embedded_view view]; - // Set a unique view identifier, so the platform view can be identified in unit tests. - platform_view.accessibilityIdentifier = - [NSString stringWithFormat:@"platform_view[%lld]", viewId]; - - FlutterTouchInterceptingView* touch_interceptor = [[FlutterTouchInterceptingView alloc] - initWithEmbeddedView:platform_view - platformViewsController:GetWeakPtr() - gestureRecognizersBlockingPolicy:gesture_recognizers_blocking_policies_[viewType]]; - - ChildClippingView* clipping_view = [[ChildClippingView alloc] initWithFrame:CGRectZero]; - [clipping_view addSubview:touch_interceptor]; - - platform_views_.emplace(viewId, PlatformViewData{ - .view = embedded_view, // - .touch_interceptor = touch_interceptor, // - .root_view = clipping_view // - }); - - result(nil); -} - -void PlatformViewsController::OnDispose(FlutterMethodCall* call, FlutterResult result) { - NSNumber* arg = [call arguments]; - int64_t viewId = [arg longLongValue]; - - if (platform_views_.count(viewId) == 0) { - result([FlutterError errorWithCode:@"unknown_view" - message:@"trying to dispose an unknown" - details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); - return; - } - // We wait for next submitFrame to dispose views. - views_to_dispose_.insert(viewId); - result(nil); -} - -void PlatformViewsController::OnAcceptGesture(FlutterMethodCall* call, FlutterResult result) { - NSDictionary* args = [call arguments]; - int64_t viewId = [args[@"id"] longLongValue]; - - if (platform_views_.count(viewId) == 0) { - result([FlutterError errorWithCode:@"unknown_view" - message:@"trying to set gesture state for an unknown view" - details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); - return; - } - - FlutterTouchInterceptingView* view = platform_views_[viewId].touch_interceptor; - [view releaseGesture]; - - result(nil); -} - -void PlatformViewsController::OnRejectGesture(FlutterMethodCall* call, FlutterResult result) { - NSDictionary* args = [call arguments]; - int64_t viewId = [args[@"id"] longLongValue]; - - if (platform_views_.count(viewId) == 0) { - result([FlutterError errorWithCode:@"unknown_view" - message:@"trying to set gesture state for an unknown view" - details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); - return; - } - - FlutterTouchInterceptingView* view = platform_views_[viewId].touch_interceptor; - [view blockGesture]; - - result(nil); -} - -void PlatformViewsController::RegisterViewFactory( - NSObject* factory, - NSString* factoryId, - FlutterPlatformViewGestureRecognizersBlockingPolicy gestureRecognizerBlockingPolicy) { - std::string idString([factoryId UTF8String]); - FML_CHECK(factories_.count(idString) == 0); - factories_[idString] = factory; - gesture_recognizers_blocking_policies_[idString] = gestureRecognizerBlockingPolicy; -} - -void PlatformViewsController::BeginFrame(SkISize frame_size) { - ResetFrameState(); - frame_size_ = frame_size; -} - -void PlatformViewsController::CancelFrame() { - ResetFrameState(); -} - -PostPrerollResult PlatformViewsController::PostPrerollAction( - const fml::RefPtr& raster_thread_merger, - bool impeller_enabled) { - // TODO(jonahwilliams): remove this once Software backend is removed for iOS Sim. -#ifdef FML_OS_IOS_SIMULATOR - const bool merge_threads = true; -#else - const bool merge_threads = !impeller_enabled; -#endif // FML_OS_IOS_SIMULATOR - - if (merge_threads) { - if (composition_order_.empty()) { - return PostPrerollResult::kSuccess; - } - if (!raster_thread_merger->IsMerged()) { - // The raster thread merger may be disabled if the rasterizer is being - // created or teared down. - // - // In such cases, the current frame is dropped, and a new frame is attempted - // with the same layer tree. - // - // Eventually, the frame is submitted once this method returns `kSuccess`. - // At that point, the raster tasks are handled on the platform thread. - CancelFrame(); - return PostPrerollResult::kSkipAndRetryFrame; - } - // If the post preroll action is successful, we will display platform views in the current - // frame. In order to sync the rendering of the platform views (quartz) with skia's rendering, - // We need to begin an explicit CATransaction. This transaction needs to be submitted - // after the current frame is submitted. - raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration); - } - return PostPrerollResult::kSuccess; -} - -void PlatformViewsController::EndFrame( - bool should_resubmit_frame, - const fml::RefPtr& raster_thread_merger, - bool impeller_enabled) { -#if FML_OS_IOS_SIMULATOR - bool run_check = true; -#else - bool run_check = !impeller_enabled; -#endif // FML_OS_IOS_SIMULATOR - if (run_check && should_resubmit_frame) { - raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration); - } -} - -void PlatformViewsController::PushFilterToVisitedPlatformViews( - const std::shared_ptr& filter, - const SkRect& filter_rect) { - for (int64_t id : visited_platform_views_) { - EmbeddedViewParams params = current_composition_params_[id]; - params.PushImageFilter(filter, filter_rect); - current_composition_params_[id] = params; - } -} - -void PlatformViewsController::PrerollCompositeEmbeddedView( - int64_t view_id, - std::unique_ptr params) { - SkRect view_bounds = SkRect::Make(frame_size_); - std::unique_ptr view; - view = std::make_unique(view_bounds); - slices_.insert_or_assign(view_id, std::move(view)); - - composition_order_.push_back(view_id); - - if (current_composition_params_.count(view_id) == 1 && - current_composition_params_[view_id] == *params.get()) { - // Do nothing if the params didn't change. - return; - } - current_composition_params_[view_id] = EmbeddedViewParams(*params.get()); - views_to_recomposite_.insert(view_id); -} - -size_t PlatformViewsController::EmbeddedViewCount() const { - return composition_order_.size(); -} - -size_t PlatformViewsController::LayerPoolSize() const { - return layer_pool_->size(); -} - -UIView* PlatformViewsController::GetPlatformViewByID(int64_t view_id) { - return [GetFlutterTouchInterceptingViewByID(view_id) embeddedView]; -} - -FlutterTouchInterceptingView* PlatformViewsController::GetFlutterTouchInterceptingViewByID( - int64_t view_id) { - if (platform_views_.empty()) { - return nil; - } - return platform_views_[view_id].touch_interceptor; -} - -long PlatformViewsController::FindFirstResponderPlatformViewId() { - for (auto const& [id, platform_view_data] : platform_views_) { - UIView* root_view = platform_view_data.root_view; - if (root_view.flt_hasFirstResponderInViewHierarchySubtree) { - return id; - } - } - return -1; -} - -void PlatformViewsController::ClipViewSetMaskView(UIView* clipView) { - FML_DCHECK([[NSThread currentThread] isMainThread]); - if (clipView.maskView) { - return; - } - CGRect frame = - CGRectMake(-clipView.frame.origin.x, -clipView.frame.origin.y, - CGRectGetWidth(flutter_view_.bounds), CGRectGetHeight(flutter_view_.bounds)); - clipView.maskView = [mask_view_pool_ getMaskViewWithFrame:frame]; -} - -// This method is only called when the `embedded_view` needs to be re-composited at the current -// frame. See: `CompositeWithParams` for details. -void PlatformViewsController::ApplyMutators(const MutatorsStack& mutators_stack, - UIView* embedded_view, - const SkRect& bounding_rect) { - if (flutter_view_ == nullptr) { - return; - } - - ResetAnchor(embedded_view.layer); - ChildClippingView* clipView = (ChildClippingView*)embedded_view.superview; - - SkMatrix transformMatrix; - NSMutableArray* blurFilters = [[NSMutableArray alloc] init]; - FML_DCHECK(!clipView.maskView || - [clipView.maskView isKindOfClass:[FlutterClippingMaskView class]]); - if (clipView.maskView) { - [mask_view_pool_ insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)]; - clipView.maskView = nil; - } - CGFloat screenScale = [UIScreen mainScreen].scale; - auto iter = mutators_stack.Begin(); - while (iter != mutators_stack.End()) { - switch ((*iter)->GetType()) { - case kTransform: { - transformMatrix.preConcat((*iter)->GetMatrix()); - break; - } - case kClipRect: { - if (ClipRectContainsPlatformViewBoundingRect((*iter)->GetRect(), bounding_rect, - transformMatrix)) { - break; - } - ClipViewSetMaskView(clipView); - [(FlutterClippingMaskView*)clipView.maskView clipRect:(*iter)->GetRect() - matrix:transformMatrix]; - break; - } - case kClipRRect: { - if (ClipRRectContainsPlatformViewBoundingRect((*iter)->GetRRect(), bounding_rect, - transformMatrix)) { - break; - } - ClipViewSetMaskView(clipView); - [(FlutterClippingMaskView*)clipView.maskView clipRRect:(*iter)->GetRRect() - matrix:transformMatrix]; - break; - } - case kClipPath: { - // TODO(cyanglaz): Find a way to pre-determine if path contains the PlatformView boudning - // rect. See `ClipRRectContainsPlatformViewBoundingRect`. - // https://github.com/flutter/flutter/issues/118650 - ClipViewSetMaskView(clipView); - [(FlutterClippingMaskView*)clipView.maskView clipPath:(*iter)->GetPath() - matrix:transformMatrix]; - break; - } - case kOpacity: - embedded_view.alpha = (*iter)->GetAlphaFloat() * embedded_view.alpha; - break; - case kBackdropFilter: { - // Only support DlBlurImageFilter for BackdropFilter. - if (!canApplyBlurBackdrop || !(*iter)->GetFilterMutation().GetFilter().asBlur()) { - break; - } - CGRect filterRect = GetCGRectFromSkRect((*iter)->GetFilterMutation().GetFilterRect()); - // `filterRect` is in global coordinates. We need to convert to local space. - filterRect = CGRectApplyAffineTransform( - filterRect, CGAffineTransformMakeScale(1 / screenScale, 1 / screenScale)); - // `filterRect` reprents the rect that should be filtered inside the `flutter_view_`. - // The `PlatformViewFilter` needs the frame inside the `clipView` that needs to be - // filtered. - if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) { - break; - } - CGRect intersection = CGRectIntersection(filterRect, clipView.frame); - CGRect frameInClipView = [flutter_view_ convertRect:intersection toView:clipView]; - // sigma_x is arbitrarily chosen as the radius value because Quartz sets - // sigma_x and sigma_y equal to each other. DlBlurImageFilter's Tile Mode - // is not supported in Quartz's gaussianBlur CAFilter, so it is not used - // to blur the PlatformView. - CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x(); - UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc] - initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; - PlatformViewFilter* filter = [[PlatformViewFilter alloc] initWithFrame:frameInClipView - blurRadius:blurRadius - visualEffectView:visualEffectView]; - if (!filter) { - canApplyBlurBackdrop = NO; - } else { - [blurFilters addObject:filter]; - } - break; - } - } - ++iter; - } - - if (canApplyBlurBackdrop) { - [clipView applyBlurBackdropFilters:blurFilters]; - } - - // The UIKit frame is set based on the logical resolution (points) instead of physical. - // (https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html). - // However, flow is based on the physical resolution. For example, 1000 pixels in flow equals - // 500 points in UIKit for devices that has screenScale of 2. We need to scale the transformMatrix - // down to the logical resoltion before applying it to the layer of PlatformView. - transformMatrix.postScale(1 / screenScale, 1 / screenScale); - - // Reverse the offset of the clipView. - // The clipView's frame includes the final translate of the final transform matrix. - // Thus, this translate needs to be reversed so the platform view can layout at the correct - // offset. - // - // Note that the transforms are not applied to the clipping paths because clipping paths happen on - // the mask view, whose origin is always (0,0) to the flutter_view. - transformMatrix.postTranslate(-clipView.frame.origin.x, -clipView.frame.origin.y); - - embedded_view.layer.transform = GetCATransform3DFromSkMatrix(transformMatrix); -} - -// Composite the PlatformView with `view_id`. -// -// Every frame, during the paint traversal of the layer tree, this method is called for all -// the PlatformViews in `views_to_recomposite_`. -// -// Note that `views_to_recomposite_` does not represent all the views in the view hierarchy, -// if a PlatformView does not change its composition parameter from last frame, it is not -// included in the `views_to_recomposite_`. -void PlatformViewsController::CompositeWithParams(int64_t view_id, - const EmbeddedViewParams& params) { - CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height()); - FlutterTouchInterceptingView* touchInterceptor = platform_views_[view_id].touch_interceptor; -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - FML_DCHECK(CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero)); - if (non_zero_origin_views_.find(view_id) == non_zero_origin_views_.end() && - !CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero)) { - non_zero_origin_views_.insert(view_id); - NSLog( - @"A Embedded PlatformView's origin is not CGPointZero.\n" - " View id: %@\n" - " View info: \n %@ \n" - "A non-zero origin might cause undefined behavior.\n" - "See https://github.com/flutter/flutter/issues/109700 for more details.\n" - "If you are the author of the PlatformView, please update the implementation of the " - "PlatformView to have a (0, 0) origin.\n" - "If you have a valid case of using a non-zero origin, " - "please leave a comment at https://github.com/flutter/flutter/issues/109700 with details.", - @(view_id), [touchInterceptor embeddedView]); - } -#endif - touchInterceptor.layer.transform = CATransform3DIdentity; - touchInterceptor.frame = frame; - touchInterceptor.alpha = 1; - - const MutatorsStack& mutatorStack = params.mutatorsStack(); - UIView* clippingView = platform_views_[view_id].root_view; - // The frame of the clipping view should be the final bounding rect. - // Because the translate matrix in the Mutator Stack also includes the offset, - // when we apply the transforms matrix in |ApplyMutators|, we need - // to remember to do a reverse translate. - const SkRect& rect = params.finalBoundingRect(); - CGFloat screenScale = [UIScreen mainScreen].scale; - clippingView.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale, - rect.width() / screenScale, rect.height() / screenScale); - ApplyMutators(mutatorStack, touchInterceptor, rect); -} - -DlCanvas* PlatformViewsController::CompositeEmbeddedView(int64_t view_id) { - return slices_[view_id]->canvas(); -} - -void PlatformViewsController::Reset() { - // Reset will only be called from the raster thread or a merged raster/platform thread. - // platform_views_ must only be modified on the platform thread, and any operations that - // read or modify platform views should occur there. - fml::TaskRunner::RunNowOrPostTask(platform_task_runner_, - [&, composition_order = composition_order_]() { - for (int64_t view_id : composition_order_) { - [platform_views_[view_id].root_view removeFromSuperview]; - } - platform_views_.clear(); - }); - - composition_order_.clear(); - slices_.clear(); - current_composition_params_.clear(); - views_to_recomposite_.clear(); - layer_pool_->RecycleLayers(); - visited_platform_views_.clear(); -} - -bool PlatformViewsController::SubmitFrame(GrDirectContext* gr_context, - const std::shared_ptr& ios_context, - std::unique_ptr background_frame) { - TRACE_EVENT0("flutter", "PlatformViewsController::SubmitFrame"); - - // No platform views to render; we're done. - if (flutter_view_ == nullptr || (composition_order_.empty() && !had_platform_views_)) { - had_platform_views_ = false; - return background_frame->Submit(); - } - had_platform_views_ = !composition_order_.empty(); - - bool did_encode = true; - LayersMap platform_view_layers; - std::vector> surface_frames; - surface_frames.reserve(composition_order_.size()); - std::unordered_map view_rects; - - for (int64_t view_id : composition_order_) { - view_rects[view_id] = current_composition_params_[view_id].finalBoundingRect(); - } - - std::unordered_map overlay_layers = - SliceViews(background_frame->Canvas(), composition_order_, slices_, view_rects); - - size_t required_overlay_layers = 0; - for (int64_t view_id : composition_order_) { - std::unordered_map::const_iterator overlay = overlay_layers.find(view_id); - if (overlay == overlay_layers.end()) { - continue; - } - required_overlay_layers++; - } - - // If there are not sufficient overlay layers, we must construct them on the platform - // thread, at least until we've refactored iOS surface creation to use IOSurfaces - // instead of CALayers. - CreateMissingOverlays(gr_context, ios_context, required_overlay_layers); - - int64_t overlay_id = 0; - for (int64_t view_id : composition_order_) { - std::unordered_map::const_iterator overlay = overlay_layers.find(view_id); - if (overlay == overlay_layers.end()) { - continue; - } - std::shared_ptr layer = GetExistingLayer(); - if (!layer) { - continue; - } - - std::unique_ptr frame = layer->surface->AcquireFrame(frame_size_); - // If frame is null, AcquireFrame already printed out an error message. - if (!frame) { - continue; - } - DlCanvas* overlay_canvas = frame->Canvas(); - int restore_count = overlay_canvas->GetSaveCount(); - overlay_canvas->Save(); - overlay_canvas->ClipRect(overlay->second); - overlay_canvas->Clear(DlColor::kTransparent()); - slices_[view_id]->render_into(overlay_canvas); - overlay_canvas->RestoreToCount(restore_count); - - // This flutter view is never the last in a frame, since we always submit the - // underlay view last. - frame->set_submit_info({.frame_boundary = false, .present_with_transaction = true}); - layer->did_submit_last_frame = frame->Encode(); - - did_encode &= layer->did_submit_last_frame; - platform_view_layers[view_id] = LayerData{ - .rect = overlay->second, // - .view_id = view_id, // - .overlay_id = overlay_id, // - .layer = layer // - }; - surface_frames.push_back(std::move(frame)); - overlay_id++; - } - - auto previous_submit_info = background_frame->submit_info(); - background_frame->set_submit_info({ - .frame_damage = previous_submit_info.frame_damage, - .buffer_damage = previous_submit_info.buffer_damage, - .present_with_transaction = true, - }); - background_frame->Encode(); - surface_frames.push_back(std::move(background_frame)); - - // Mark all layers as available, so they can be used in the next frame. - std::vector> unused_layers = layer_pool_->RemoveUnusedLayers(); - layer_pool_->RecycleLayers(); - - auto task = [&, // - platform_view_layers = std::move(platform_view_layers), // - current_composition_params = current_composition_params_, // - views_to_recomposite = views_to_recomposite_, // - composition_order = composition_order_, // - unused_layers = std::move(unused_layers), // - surface_frames = std::move(surface_frames) // - ]() mutable { - PerformSubmit(platform_view_layers, // - current_composition_params, // - views_to_recomposite, // - composition_order, // - unused_layers, // - surface_frames // - ); - }; - - fml::TaskRunner::RunNowOrPostTask(platform_task_runner_, fml::MakeCopyable(std::move(task))); - - return did_encode; -} - -void PlatformViewsController::CreateMissingOverlays(GrDirectContext* gr_context, - const std::shared_ptr& ios_context, - size_t required_overlay_layers) { - TRACE_EVENT0("flutter", "PlatformViewsController::CreateMissingLayers"); - - if (required_overlay_layers <= layer_pool_->size()) { - return; - } - auto missing_layer_count = required_overlay_layers - layer_pool_->size(); - - // If the raster thread isn't merged, create layers on the platform thread and block until - // complete. - auto latch = std::make_shared(1u); - fml::TaskRunner::RunNowOrPostTask(platform_task_runner_, [&]() { - for (auto i = 0u; i < missing_layer_count; i++) { - CreateLayer(gr_context, // - ios_context, // - ((FlutterView*)flutter_view_).pixelFormat // - ); - } - latch->CountDown(); - }); - if (![[NSThread currentThread] isMainThread]) { - latch->Wait(); - } -} - -/// Update the buffers and mutate the platform views in CATransaction on the platform thread. -void PlatformViewsController::PerformSubmit( - const LayersMap& platform_view_layers, - std::unordered_map& current_composition_params, - const std::unordered_set& views_to_recomposite, - const std::vector& composition_order, - const std::vector>& unused_layers, - const std::vector>& surface_frames) { - TRACE_EVENT0("flutter", "PlatformViewsController::PerformSubmit"); - FML_DCHECK([[NSThread currentThread] isMainThread]); - - [CATransaction begin]; - - // Configure Flutter overlay views. - for (const auto& [view_id, layer_data] : platform_view_layers) { - layer_data.layer->UpdateViewState(flutter_view_, // - layer_data.rect, // - layer_data.view_id, // - layer_data.overlay_id // - ); - } - - // Dispose unused Flutter Views. - for (auto& view : GetViewsToDispose()) { - [view removeFromSuperview]; - } - - // Composite Platform Views. - for (int64_t view_id : views_to_recomposite) { - CompositeWithParams(view_id, current_composition_params[view_id]); - } - - // Present callbacks. - for (const auto& frame : surface_frames) { - frame->Submit(); - } - - // If a layer was allocated in the previous frame, but it's not used in the current frame, - // then it can be removed from the scene. - RemoveUnusedLayers(unused_layers, composition_order); - - // Organize the layers by their z indexes. - BringLayersIntoView(platform_view_layers, composition_order); - - [CATransaction commit]; -} - -void PlatformViewsController::BringLayersIntoView(const LayersMap& layer_map, - const std::vector& composition_order) { - FML_DCHECK(flutter_view_); - UIView* flutter_view = flutter_view_; - - previous_composition_order_.clear(); - NSMutableArray* desired_platform_subviews = [NSMutableArray array]; - for (int64_t platform_view_id : composition_order) { - previous_composition_order_.push_back(platform_view_id); - UIView* platform_view_root = platform_views_[platform_view_id].root_view; - if (platform_view_root != nil) { - [desired_platform_subviews addObject:platform_view_root]; - } - - auto maybe_layer_data = layer_map.find(platform_view_id); - if (maybe_layer_data != layer_map.end()) { - auto view = maybe_layer_data->second.layer->overlay_view_wrapper; - if (view != nil) { - [desired_platform_subviews addObject:view]; - } - } - } - - NSSet* desired_platform_subviews_set = [NSSet setWithArray:desired_platform_subviews]; - NSArray* existing_platform_subviews = [flutter_view.subviews - filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, - NSDictionary* bindings) { - return [desired_platform_subviews_set containsObject:object]; - }]]; - - // Manipulate view hierarchy only if needed, to address a performance issue where - // `BringLayersIntoView` is called even when view hierarchy stays the same. - // See: https://github.com/flutter/flutter/issues/121833 - // TODO(hellohuanlin): investigate if it is possible to skip unnecessary BringLayersIntoView. - if (![desired_platform_subviews isEqualToArray:existing_platform_subviews]) { - for (UIView* subview in desired_platform_subviews) { - // `addSubview` will automatically reorder subview if it is already added. - [flutter_view addSubview:subview]; - } - } -} - -std::shared_ptr PlatformViewsController::GetExistingLayer() { - return layer_pool_->GetNextLayer(); -} - -void PlatformViewsController::CreateLayer(GrDirectContext* gr_context, - const std::shared_ptr& ios_context, - MTLPixelFormat pixel_format) { - layer_pool_->CreateLayer(gr_context, ios_context, pixel_format); -} - -void PlatformViewsController::RemoveUnusedLayers( - const std::vector>& unused_layers, - const std::vector& composition_order) { - for (const std::shared_ptr& layer : unused_layers) { - [layer->overlay_view_wrapper removeFromSuperview]; - } - - std::unordered_set composition_order_set; - for (int64_t view_id : composition_order) { - composition_order_set.insert(view_id); - } - // Remove unused platform views. - for (int64_t view_id : previous_composition_order_) { - if (composition_order_set.find(view_id) == composition_order_set.end()) { - UIView* platform_view_root = platform_views_[view_id].root_view; - [platform_view_root removeFromSuperview]; - } - } -} - -std::vector PlatformViewsController::GetViewsToDispose() { - std::vector views; - if (views_to_dispose_.empty()) { - return views; - } - - std::unordered_set views_to_composite(composition_order_.begin(), - composition_order_.end()); - std::unordered_set views_to_delay_dispose; - for (int64_t viewId : views_to_dispose_) { - if (views_to_composite.count(viewId)) { - views_to_delay_dispose.insert(viewId); - continue; - } - UIView* root_view = platform_views_[viewId].root_view; - views.push_back(root_view); - current_composition_params_.erase(viewId); - views_to_recomposite_.erase(viewId); - platform_views_.erase(viewId); - } - views_to_dispose_ = std::move(views_to_delay_dispose); - return views; -} - -void PlatformViewsController::ResetFrameState() { - slices_.clear(); - composition_order_.clear(); - visited_platform_views_.clear(); -} - -} // namespace flutter diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index 6983ac83f08cf..d22fc3fb47743 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -13,14 +13,14 @@ namespace flutter { class IOSExternalViewEmbedder : public ExternalViewEmbedder { public: IOSExternalViewEmbedder( - const std::shared_ptr& platform_views_controller, + __weak FlutterPlatformViewsController* platform_views_controller, const std::shared_ptr& context); // |ExternalViewEmbedder| virtual ~IOSExternalViewEmbedder() override; private: - const std::shared_ptr& platform_views_controller_; + __weak FlutterPlatformViewsController* platform_views_controller_; std::shared_ptr ios_context_; // |ExternalViewEmbedder| diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index a2f5ff9c2b58e..ebde36386b3c1 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -12,7 +12,7 @@ namespace flutter { IOSExternalViewEmbedder::IOSExternalViewEmbedder( - const std::shared_ptr& platform_views_controller, + __weak FlutterPlatformViewsController* platform_views_controller, const std::shared_ptr& context) : platform_views_controller_(platform_views_controller), ios_context_(context) { FML_CHECK(ios_context_); @@ -31,7 +31,7 @@ void IOSExternalViewEmbedder::CancelFrame() { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::CancelFrame"); FML_CHECK(platform_views_controller_); - platform_views_controller_->CancelFrame(); + [platform_views_controller_ cancelFrame]; } // |ExternalViewEmbedder| @@ -42,7 +42,7 @@ // |ExternalViewEmbedder| void IOSExternalViewEmbedder::PrepareFlutterView(SkISize frame_size, double device_pixel_ratio) { FML_CHECK(platform_views_controller_); - platform_views_controller_->BeginFrame(frame_size); + [platform_views_controller_ beginFrameWithSize:frame_size]; } // |ExternalViewEmbedder| @@ -51,7 +51,7 @@ std::unique_ptr params) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::PrerollCompositeEmbeddedView"); FML_CHECK(platform_views_controller_); - platform_views_controller_->PrerollCompositeEmbeddedView(view_id, std::move(params)); + [platform_views_controller_ prerollCompositeEmbeddedView:view_id withParams:std::move(params)]; } // |ExternalViewEmbedder| @@ -59,8 +59,10 @@ const fml::RefPtr& raster_thread_merger) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::PostPrerollAction"); FML_CHECK(platform_views_controller_); - PostPrerollResult result = platform_views_controller_->PostPrerollAction( - raster_thread_merger, ios_context_->GetBackend() != IOSRenderingBackend::kSkia); + BOOL impeller_enabled = ios_context_->GetBackend() != IOSRenderingBackend::kSkia; + PostPrerollResult result = + [platform_views_controller_ postPrerollActionWithThreadMerger:raster_thread_merger + impellerEnabled:impeller_enabled]; return result; } @@ -68,7 +70,7 @@ DlCanvas* IOSExternalViewEmbedder::CompositeEmbeddedView(int64_t view_id) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::CompositeEmbeddedView"); FML_CHECK(platform_views_controller_); - return platform_views_controller_->CompositeEmbeddedView(view_id); + return [platform_views_controller_ compositeEmbeddedViewWithId:view_id]; } // |ExternalViewEmbedder| @@ -83,7 +85,9 @@ // Properly support multi-view in the future. FML_DCHECK(flutter_view_id == kFlutterImplicitViewId); FML_CHECK(platform_views_controller_); - platform_views_controller_->SubmitFrame(context, ios_context_, std::move(frame)); + [platform_views_controller_ submitFrame:std::move(frame) + withIosContext:ios_context_ + grContext:context]; TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::DidSubmitFrame"); } @@ -92,8 +96,10 @@ bool should_resubmit_frame, const fml::RefPtr& raster_thread_merger) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::EndFrame"); - platform_views_controller_->EndFrame(should_resubmit_frame, raster_thread_merger, - ios_context_->GetBackend() != IOSRenderingBackend::kSkia); + BOOL impeller_enabled = ios_context_->GetBackend() != IOSRenderingBackend::kSkia; + [platform_views_controller_ endFrameWithResubmit:should_resubmit_frame + threadMerger:raster_thread_merger + impellerEnabled:impeller_enabled]; } // |ExternalViewEmbedder| @@ -110,12 +116,12 @@ void IOSExternalViewEmbedder::PushFilterToVisitedPlatformViews( const std::shared_ptr& filter, const SkRect& filter_rect) { - platform_views_controller_->PushFilterToVisitedPlatformViews(filter, filter_rect); + [platform_views_controller_ pushFilterToVisitedPlatformViews:filter withRect:filter_rect]; } // |ExternalViewEmbedder| void IOSExternalViewEmbedder::PushVisitedPlatformView(int64_t view_id) { - platform_views_controller_->PushVisitedPlatformView(view_id); + [platform_views_controller_ pushVisitedPlatformViewId:view_id]; } } // namespace flutter diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index 0e65e6174f594..4e1da467d22bd 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -40,13 +40,13 @@ class PlatformViewIOS final : public PlatformView { public: PlatformViewIOS(PlatformView::Delegate& delegate, const std::shared_ptr& context, - const std::shared_ptr& platform_views_controller, + __weak FlutterPlatformViewsController* platform_views_controller, const flutter::TaskRunners& task_runners); explicit PlatformViewIOS( PlatformView::Delegate& delegate, IOSRenderingAPI rendering_api, - const std::shared_ptr& platform_views_controller, + __weak FlutterPlatformViewsController* platform_views_controller, const flutter::TaskRunners& task_runners, const std::shared_ptr& worker_task_runner, const std::shared_ptr& is_gpu_disabled_sync_switch); @@ -137,7 +137,7 @@ class PlatformViewIOS final : public PlatformView { std::mutex ios_surface_mutex_; std::unique_ptr ios_surface_; std::shared_ptr ios_context_; - const std::shared_ptr& platform_views_controller_; + __weak FlutterPlatformViewsController* platform_views_controller_; AccessibilityBridgeManager accessibility_bridge_; ScopedObserver dealloc_view_controller_observer_; std::vector platform_resolved_locale_; diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index f651d00ec8eca..b726fd8fc1ee4 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -41,11 +41,10 @@ accessibility_bridge_.reset(); } -PlatformViewIOS::PlatformViewIOS( - PlatformView::Delegate& delegate, - const std::shared_ptr& context, - const std::shared_ptr& platform_views_controller, - const flutter::TaskRunners& task_runners) +PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate, + const std::shared_ptr& context, + __weak FlutterPlatformViewsController* platform_views_controller, + const flutter::TaskRunners& task_runners) : PlatformView(delegate, task_runners), ios_context_(context), platform_views_controller_(platform_views_controller), @@ -56,7 +55,7 @@ new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {} PlatformViewIOS::PlatformViewIOS( PlatformView::Delegate& delegate, IOSRenderingAPI rendering_api, - const std::shared_ptr& platform_views_controller, + __weak FlutterPlatformViewsController* platform_views_controller, const flutter::TaskRunners& task_runners, const std::shared_ptr& worker_task_runner, const std::shared_ptr& is_gpu_disabled_sync_switch) @@ -209,7 +208,7 @@ new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {} if (!owner_controller_) { return; } - owner_controller_.platformViewsController->Reset(); + [owner_controller_.platformViewsController reset]; [owner_controller_.restorationPlugin reset]; } diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index f0df9973f49ee..8ca474222d39e 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -164,6 +164,9 @@ typedef enum { kFlutterSemanticsActionSetText = 1 << 21, /// Request that the respective focusable widget gain input focus. kFlutterSemanticsActionFocus = 1 << 22, + /// Request that scrolls the current scrollable container to a given scroll + /// offset. + kFlutterSemanticsActionScrollToOffset = 1 << 23, } FlutterSemanticsAction; /// The set of properties that may be associated with a semantics node. diff --git a/shell/platform/fuchsia/dart-pkg/fuchsia/pubspec.yaml b/shell/platform/fuchsia/dart-pkg/fuchsia/pubspec.yaml index 85d01ce1515b9..fdacaaf5bde03 100644 --- a/shell/platform/fuchsia/dart-pkg/fuchsia/pubspec.yaml +++ b/shell/platform/fuchsia/dart-pkg/fuchsia/pubspec.yaml @@ -3,4 +3,4 @@ # found in the LICENSE file. environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/dart-pkg/zircon/pubspec.yaml b/shell/platform/fuchsia/dart-pkg/zircon/pubspec.yaml index c75e7f8ff6a4a..ac72505fe6e92 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/pubspec.yaml +++ b/shell/platform/fuchsia/dart-pkg/zircon/pubspec.yaml @@ -5,7 +5,7 @@ name: zircon environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 # Uncomment block for local testing diff --git a/shell/platform/fuchsia/dart-pkg/zircon_ffi/pubspec.yaml b/shell/platform/fuchsia/dart-pkg/zircon_ffi/pubspec.yaml index e30ca0196f5a7..f1d8c199db0cd 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon_ffi/pubspec.yaml +++ b/shell/platform/fuchsia/dart-pkg/zircon_ffi/pubspec.yaml @@ -1,7 +1,7 @@ name: zircon_ffi environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 dependencies: ffi: ^1.0.0 diff --git a/shell/platform/fuchsia/dart_runner/embedder/pubspec.yaml b/shell/platform/fuchsia/dart_runner/embedder/pubspec.yaml index d1ccbe7700dc5..6ef1940491851 100644 --- a/shell/platform/fuchsia/dart_runner/embedder/pubspec.yaml +++ b/shell/platform/fuchsia/dart_runner/embedder/pubspec.yaml @@ -6,5 +6,5 @@ # template in BUILD.gn. environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/dart_runner/vmservice/pubspec.yaml b/shell/platform/fuchsia/dart_runner/vmservice/pubspec.yaml index df2ce1ab10dbf..dfe2136345352 100644 --- a/shell/platform/fuchsia/dart_runner/vmservice/pubspec.yaml +++ b/shell/platform/fuchsia/dart_runner/vmservice/pubspec.yaml @@ -3,5 +3,5 @@ # found in the LICENSE file. environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/flutter/accessibility_bridge.cc b/shell/platform/fuchsia/flutter/accessibility_bridge.cc index b9f443035a37f..987b9303bace1 100644 --- a/shell/platform/fuchsia/flutter/accessibility_bridge.cc +++ b/shell/platform/fuchsia/flutter/accessibility_bridge.cc @@ -161,6 +161,9 @@ std::string NodeActionsToString(const flutter::SemanticsNode& node) { if (node.HasAction(flutter::SemanticsAction::kScrollUp)) { output += "kScrollUp|"; } + if (node.HasAction(flutter::SemanticsAction::kScrollToOffset)) { + output += "kScrollToOffset|"; + } if (node.HasAction(flutter::SemanticsAction::kSetSelection)) { output += "kSetSelection|"; } diff --git a/shell/platform/fuchsia/flutter/kernel/pubspec.yaml b/shell/platform/fuchsia/flutter/kernel/pubspec.yaml index 85d01ce1515b9..fdacaaf5bde03 100644 --- a/shell/platform/fuchsia/flutter/kernel/pubspec.yaml +++ b/shell/platform/fuchsia/flutter/kernel/pubspec.yaml @@ -3,4 +3,4 @@ # found in the LICENSE file. environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/pubspec.yaml index 89f565db2969b..999c2898734e2 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/pubspec.yaml +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/pubspec.yaml @@ -5,4 +5,4 @@ name: child_view2 environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/pubspec.yaml index 1ee7f0c30401c..418f4a5f0179a 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/pubspec.yaml +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/pubspec.yaml @@ -5,4 +5,4 @@ name: parent-view2 environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/flutter/tests/integration/mouse-input/mouse-input-view/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/mouse-input/mouse-input-view/pubspec.yaml index 40e52bb3bbc54..1b4c748f4ed7c 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/mouse-input/mouse-input-view/pubspec.yaml +++ b/shell/platform/fuchsia/flutter/tests/integration/mouse-input/mouse-input-view/pubspec.yaml @@ -5,4 +5,4 @@ name: mouse-input-view environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/pubspec.yaml index 21d9b7d9c0917..1c7aebb632d23 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/pubspec.yaml +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/pubspec.yaml @@ -5,4 +5,4 @@ name: text-input-view environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/pubspec.yaml index e929bdaaa7518..88d86708587c5 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/pubspec.yaml +++ b/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/pubspec.yaml @@ -5,4 +5,4 @@ name: embedding-flutter-view environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/flutter/tests/integration/touch-input/touch-input-view/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/touch-input/touch-input-view/pubspec.yaml index 7fc83f8c32fd0..4ba22fab5b134 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/touch-input/touch-input-view/pubspec.yaml +++ b/shell/platform/fuchsia/flutter/tests/integration/touch-input/touch-input-view/pubspec.yaml @@ -5,4 +5,4 @@ name: touch-input-view environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/shell/platform/fuchsia/runtime/dart/profiler_symbols/pubspec.yaml b/shell/platform/fuchsia/runtime/dart/profiler_symbols/pubspec.yaml index 7076e2a537f44..50ff8e43b8af2 100644 --- a/shell/platform/fuchsia/runtime/dart/profiler_symbols/pubspec.yaml +++ b/shell/platform/fuchsia/runtime/dart/profiler_symbols/pubspec.yaml @@ -4,7 +4,7 @@ name: profiler_symbols environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 version: 0 description: Extracts a minimal symbols table for the Dart VM profiler author: Dart Team diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index b00bab8cedbca..b2cdd11aed99a 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 14285debb0c59..b71b0c74f2479 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -116,6 +116,7 @@ source_set("flutter_linux_sources") { "fl_key_channel_responder.cc", "fl_key_embedder_responder.cc", "fl_key_event.cc", + "fl_key_event_channel.cc", "fl_keyboard_channel.cc", "fl_keyboard_handler.cc", "fl_keyboard_layout.cc", @@ -230,6 +231,7 @@ executable("flutter_linux_unittests") { "fl_method_codec_test.cc", "fl_method_response_test.cc", "fl_pixel_buffer_texture_test.cc", + "fl_platform_channel_test.cc", "fl_platform_handler_test.cc", "fl_plugin_registrar_test.cc", "fl_pointer_manager_test.cc", @@ -248,11 +250,10 @@ executable("flutter_linux_unittests") { "fl_view_test.cc", "fl_window_state_monitor_test.cc", "key_mapping_test.cc", + "testing/fl_mock_binary_messenger.cc", "testing/fl_test.cc", "testing/fl_test_gtk_logs.cc", "testing/fl_test_gtk_logs.h", - "testing/mock_binary_messenger.cc", - "testing/mock_binary_messenger_response_handle.cc", "testing/mock_engine.cc", "testing/mock_epoxy.cc", "testing/mock_im_context.cc", diff --git a/shell/platform/linux/fl_basic_message_channel.cc b/shell/platform/linux/fl_basic_message_channel.cc index 7d2b5afe60a6a..b7552be5814a8 100644 --- a/shell/platform/linux/fl_basic_message_channel.cc +++ b/shell/platform/linux/fl_basic_message_channel.cc @@ -103,8 +103,8 @@ static void message_cb(FlBinaryMessenger* messenger, static void message_response_cb(GObject* object, GAsyncResult* result, gpointer user_data) { - GTask* task = G_TASK(user_data); - g_task_return_pointer(task, result, g_object_unref); + g_autoptr(GTask) task = G_TASK(user_data); + g_task_return_pointer(task, g_object_ref(result), g_object_unref); } // Called when the channel handler is closed. @@ -239,7 +239,7 @@ G_MODULE_EXPORT void fl_basic_message_channel_send(FlBasicMessageChannel* self, fl_message_codec_encode_message(self->codec, message, &error); if (data == nullptr) { if (task != nullptr) { - g_task_return_error(task, error); + g_task_return_error(task, g_error_copy(error)); } return; } @@ -257,8 +257,12 @@ G_MODULE_EXPORT FlValue* fl_basic_message_channel_send_finish( g_return_val_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self), nullptr); g_return_val_if_fail(g_task_is_valid(result, self), nullptr); - g_autoptr(GTask) task = G_TASK(result); - GAsyncResult* r = G_ASYNC_RESULT(g_task_propagate_pointer(task, nullptr)); + GTask* task = G_TASK(result); + g_autoptr(GAsyncResult) r = + G_ASYNC_RESULT(g_task_propagate_pointer(task, error)); + if (r == nullptr) { + return nullptr; + } g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish(self->messenger, r, error); diff --git a/shell/platform/linux/fl_basic_message_channel_test.cc b/shell/platform/linux/fl_basic_message_channel_test.cc index 4cdcca136759f..a718486ee4716 100644 --- a/shell/platform/linux/fl_basic_message_channel_test.cc +++ b/shell/platform/linux/fl_basic_message_channel_test.cc @@ -43,7 +43,7 @@ TEST(FlBasicMessageChannelTest, SendMessageWithoutResponse) { g_bytes_new(message->message, message->message_size); g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new(); - FlValue* message_value = fl_message_codec_decode_message( + g_autoptr(FlValue) message_value = fl_message_codec_decode_message( FL_MESSAGE_CODEC(codec), message_bytes, nullptr); EXPECT_EQ(fl_value_get_type(message_value), FL_VALUE_TYPE_STRING); EXPECT_STREQ(fl_value_get_string(message_value), "Hello World!"); @@ -222,3 +222,35 @@ TEST(FlBasicMessageChannelTest, SendNullMessageWithResponse) { // Blocks here until null_message_response_cb is called. g_main_loop_run(loop); } + +// Called when the message response is received in the CustomType test. +static void custom_type_response_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + g_autoptr(FlValue) message = fl_basic_message_channel_send_finish( + FL_BASIC_MESSAGE_CHANNEL(object), result, &error); + EXPECT_EQ(message, nullptr); + EXPECT_NE(error, nullptr); + EXPECT_STREQ(error->message, "Custom value not implemented"); + + g_main_loop_quit(static_cast(user_data)); +} + +// Checks sending a message with a custom type generates an error. +TEST(FlBasicMessageChannelTest, CustomType) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + // Attempt to send an integer with the string codec. + g_autoptr(FlEngine) engine = make_mock_engine(); + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new(); + g_autoptr(FlBasicMessageChannel) channel = fl_basic_message_channel_new( + messenger, "test/echo", FL_MESSAGE_CODEC(codec)); + g_autoptr(FlValue) message = fl_value_new_custom(42, nullptr, nullptr); + fl_basic_message_channel_send(channel, message, nullptr, + custom_type_response_cb, loop); + + // Blocks here until custom_type_response_cb is called. + g_main_loop_run(loop); +} diff --git a/shell/platform/linux/fl_binary_messenger.cc b/shell/platform/linux/fl_binary_messenger.cc index 16dcd2b86bbc1..4453456ec1113 100644 --- a/shell/platform/linux/fl_binary_messenger.cc +++ b/shell/platform/linux/fl_binary_messenger.cc @@ -260,8 +260,8 @@ static gboolean send_response(FlBinaryMessenger* messenger, static void platform_message_ready_cb(GObject* object, GAsyncResult* result, gpointer user_data) { - GTask* task = G_TASK(user_data); - g_task_return_pointer(task, result, g_object_unref); + g_autoptr(GTask) task = G_TASK(user_data); + g_task_return_pointer(task, g_object_ref(result), g_object_unref); } static void send_on_channel(FlBinaryMessenger* messenger, @@ -290,8 +290,12 @@ static GBytes* send_on_channel_finish(FlBinaryMessenger* messenger, FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(messenger); g_return_val_if_fail(g_task_is_valid(result, self), FALSE); - g_autoptr(GTask) task = G_TASK(result); - GAsyncResult* r = G_ASYNC_RESULT(g_task_propagate_pointer(task, nullptr)); + GTask* task = G_TASK(result); + g_autoptr(GAsyncResult) r = + G_ASYNC_RESULT(g_task_propagate_pointer(task, error)); + if (r == nullptr) { + return nullptr; + } g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); if (engine == nullptr) { diff --git a/shell/platform/linux/fl_binary_messenger_test.cc b/shell/platform/linux/fl_binary_messenger_test.cc index 133f6e4b57c20..8f03eb514057c 100644 --- a/shell/platform/linux/fl_binary_messenger_test.cc +++ b/shell/platform/linux/fl_binary_messenger_test.cc @@ -16,9 +16,34 @@ #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" #include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h" #include "flutter/shell/platform/linux/testing/mock_renderer.h" +G_DECLARE_FINAL_TYPE(FlFakeBinaryMessengerResponseHandle, + fl_fake_binary_messenger_response_handle, + FL, + FAKE_BINARY_MESSENGER_RESPONSE_HANDLE, + FlBinaryMessengerResponseHandle) + +struct _FlFakeBinaryMessengerResponseHandle { + FlBinaryMessengerResponseHandle parent_instance; +}; + +G_DEFINE_TYPE(FlFakeBinaryMessengerResponseHandle, + fl_fake_binary_messenger_response_handle, + fl_binary_messenger_response_handle_get_type()); + +static void fl_fake_binary_messenger_response_handle_class_init( + FlFakeBinaryMessengerResponseHandleClass* klass) {} + +static void fl_fake_binary_messenger_response_handle_init( + FlFakeBinaryMessengerResponseHandle* self) {} + +FlFakeBinaryMessengerResponseHandle* +fl_fake_binary_messenger_response_handle_new() { + return FL_FAKE_BINARY_MESSENGER_RESPONSE_HANDLE( + g_object_new(fl_fake_binary_messenger_response_handle_get_type(), NULL)); +} + G_DECLARE_FINAL_TYPE(FlFakeBinaryMessenger, fl_fake_binary_messenger, FL, @@ -55,7 +80,7 @@ static gboolean send_message_cb(gpointer user_data) { g_autoptr(GBytes) message = g_bytes_new(text, strlen(text)); self->message_handler(FL_BINARY_MESSENGER(self), "CHANNEL", message, FL_BINARY_MESSENGER_RESPONSE_HANDLE( - fl_mock_binary_messenger_response_handle_new()), + fl_fake_binary_messenger_response_handle_new()), self->message_handler_user_data); return FALSE; @@ -83,7 +108,7 @@ static gboolean send_response(FlBinaryMessenger* messenger, GError** error) { FlFakeBinaryMessenger* self = FL_FAKE_BINARY_MESSENGER(messenger); - EXPECT_TRUE(FL_IS_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle)); + EXPECT_TRUE(FL_IS_FAKE_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle)); g_autofree gchar* text = g_strndup(static_cast(g_bytes_get_data(response, nullptr)), diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 757cc5d893937..faf43fdfb65e9 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -7,95 +7,12 @@ #include #include -#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" +#include "flutter/shell/platform/linux/fl_key_event_channel.h" -static constexpr char kChannelName[] = "flutter/keyevent"; -static constexpr char kTypeKey[] = "type"; -static constexpr char kTypeValueUp[] = "keyup"; -static constexpr char kTypeValueDown[] = "keydown"; -static constexpr char kKeymapKey[] = "keymap"; -static constexpr char kKeyCodeKey[] = "keyCode"; -static constexpr char kScanCodeKey[] = "scanCode"; -static constexpr char kModifiersKey[] = "modifiers"; -static constexpr char kToolkitKey[] = "toolkit"; -static constexpr char kSpecifiedLogicalKey[] = "specifiedLogicalKey"; -static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues"; - -static constexpr char kGtkToolkit[] = "gtk"; -static constexpr char kLinuxKeymap[] = "linux"; - -/* Declare and define FlKeyChannelUserData */ - -/** - * FlKeyChannelUserData: - * The user_data used when #FlKeyChannelResponder sends message through the - * channel. - */ -G_DECLARE_FINAL_TYPE(FlKeyChannelUserData, - fl_key_channel_user_data, - FL, - KEY_CHANNEL_USER_DATA, - GObject); - -struct _FlKeyChannelUserData { - GObject parent_instance; - - // The current responder. - GWeakRef responder; - // The callback provided by the caller #FlKeyboardHandler. - FlKeyChannelResponderAsyncCallback callback; - // The user_data provided by the caller #FlKeyboardHandler. - gpointer user_data; -}; - -// Definition for FlKeyChannelUserData private class. -G_DEFINE_TYPE(FlKeyChannelUserData, fl_key_channel_user_data, G_TYPE_OBJECT) - -// Dispose method for FlKeyChannelUserData private class. -static void fl_key_channel_user_data_dispose(GObject* object) { - g_return_if_fail(FL_IS_KEY_CHANNEL_USER_DATA(object)); - FlKeyChannelUserData* self = FL_KEY_CHANNEL_USER_DATA(object); - - g_weak_ref_clear(&self->responder); - - G_OBJECT_CLASS(fl_key_channel_user_data_parent_class)->dispose(object); -} - -// Class initialization method for FlKeyChannelUserData private class. -static void fl_key_channel_user_data_class_init( - FlKeyChannelUserDataClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_channel_user_data_dispose; -} - -// Instance initialization method for FlKeyChannelUserData private class. -static void fl_key_channel_user_data_init(FlKeyChannelUserData* self) {} - -// Creates a new FlKeyChannelUserData private class with all information. -// -// The callback and the user_data might be nullptr. -static FlKeyChannelUserData* fl_key_channel_user_data_new( - FlKeyChannelResponder* responder, - FlKeyChannelResponderAsyncCallback callback, - gpointer user_data) { - FlKeyChannelUserData* self = FL_KEY_CHANNEL_USER_DATA( - g_object_new(fl_key_channel_user_data_get_type(), nullptr)); - - g_weak_ref_init(&self->responder, responder); - self->callback = callback; - self->user_data = user_data; - return self; -} - -/* Define FlKeyChannelResponder */ - -// Definition of the FlKeyChannelResponder GObject class. struct _FlKeyChannelResponder { GObject parent_instance; - FlBasicMessageChannel* channel; - - FlKeyChannelResponderMock* mock; + FlKeyEventChannel* channel; }; G_DEFINE_TYPE(FlKeyChannelResponder, fl_key_channel_responder, G_TYPE_OBJECT) @@ -105,31 +22,17 @@ G_DEFINE_TYPE(FlKeyChannelResponder, fl_key_channel_responder, G_TYPE_OBJECT) static void handle_response(GObject* object, GAsyncResult* result, gpointer user_data) { - g_autoptr(FlKeyChannelUserData) data = FL_KEY_CHANNEL_USER_DATA(user_data); - - g_autoptr(FlKeyChannelResponder) self = - FL_KEY_CHANNEL_RESPONDER(g_weak_ref_get(&data->responder)); - if (self == nullptr) { - return; - } + g_autoptr(GTask) task = G_TASK(user_data); + gboolean handled = FALSE; g_autoptr(GError) error = nullptr; - FlBasicMessageChannel* messageChannel = FL_BASIC_MESSAGE_CHANNEL(object); - FlValue* message = - fl_basic_message_channel_send_finish(messageChannel, result, &error); - if (self->mock != nullptr && self->mock->value_converter != nullptr) { - message = self->mock->value_converter(message); - } - bool handled = false; - if (error != nullptr) { + if (!fl_key_event_channel_send_finish(object, result, &handled, &error)) { g_warning("Unable to retrieve framework response: %s", error->message); - } else { - g_autoptr(FlValue) handled_value = - fl_value_lookup_string(message, "handled"); - handled = fl_value_get_bool(handled_value); } - data->callback(handled, data->user_data); + gboolean* return_value = g_new0(gboolean, 1); + *return_value = handled; + g_task_return_pointer(task, return_value, g_free); } // Disposes of an FlKeyChannelResponder instance. @@ -152,40 +55,33 @@ static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {} // Creates a new FlKeyChannelResponder instance, with a messenger used to send // messages to the framework, and an FlTextInputHandler that is used to handle -// key events that the framework doesn't handle. Mainly for testing purposes, it -// also takes an optional callback to call when a response is received, and an -// optional channel name to use when sending messages. +// key events that the framework doesn't handle. FlKeyChannelResponder* fl_key_channel_responder_new( - FlBinaryMessenger* messenger, - FlKeyChannelResponderMock* mock) { + FlBinaryMessenger* messenger) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER( g_object_new(fl_key_channel_responder_get_type(), nullptr)); - self->mock = mock; - g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - const char* channel_name = - mock == nullptr ? kChannelName : mock->channel_name; - self->channel = fl_basic_message_channel_new(messenger, channel_name, - FL_MESSAGE_CODEC(codec)); + self->channel = fl_key_event_channel_new(messenger); return self; } -void fl_key_channel_responder_handle_event( - FlKeyChannelResponder* self, - FlKeyEvent* event, - uint64_t specified_logical_key, - FlKeyChannelResponderAsyncCallback callback, - gpointer user_data) { +void fl_key_channel_responder_handle_event(FlKeyChannelResponder* self, + FlKeyEvent* event, + uint64_t specified_logical_key, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); - const gchar* type = - fl_key_event_get_is_press(event) ? kTypeValueDown : kTypeValueUp; + FlKeyEventType type = fl_key_event_get_is_press(event) + ? FL_KEY_EVENT_TYPE_KEYDOWN + : FL_KEY_EVENT_TYPE_KEYUP; int64_t scan_code = fl_key_event_get_keycode(event); - int64_t unicode_scarlar_values = + int64_t unicode_scalar_values = gdk_keyval_to_unicode(fl_key_event_get_keyval(event)); // For most modifier keys, GTK keeps track of the "pressed" state of the @@ -234,29 +130,25 @@ void fl_key_channel_responder_handle_event( state |= (shift_lock_pressed || caps_lock_pressed) ? GDK_LOCK_MASK : 0x0; state |= num_lock_pressed ? GDK_MOD2_MASK : 0x0; - g_autoptr(FlValue) message = fl_value_new_map(); - fl_value_set_string_take(message, kTypeKey, fl_value_new_string(type)); - fl_value_set_string_take(message, kKeymapKey, - fl_value_new_string(kLinuxKeymap)); - fl_value_set_string_take(message, kScanCodeKey, fl_value_new_int(scan_code)); - fl_value_set_string_take(message, kToolkitKey, - fl_value_new_string(kGtkToolkit)); - fl_value_set_string_take(message, kKeyCodeKey, - fl_value_new_int(fl_key_event_get_keyval(event))); - fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(state)); - if (unicode_scarlar_values != 0) { - fl_value_set_string_take(message, kUnicodeScalarValuesKey, - fl_value_new_int(unicode_scarlar_values)); - } + fl_key_event_channel_send( + self->channel, type, scan_code, fl_key_event_get_keyval(event), state, + unicode_scalar_values, specified_logical_key, nullptr, handle_response, + g_task_new(self, cancellable, callback, user_data)); +} - if (specified_logical_key != 0) { - fl_value_set_string_take(message, kSpecifiedLogicalKey, - fl_value_new_int(specified_logical_key)); +gboolean fl_key_channel_responder_handle_event_finish( + FlKeyChannelResponder* self, + GAsyncResult* result, + gboolean* handled, + GError** error) { + g_return_val_if_fail(g_task_is_valid(result, self), FALSE); + + g_autofree gboolean* return_value = + static_cast(g_task_propagate_pointer(G_TASK(result), error)); + if (return_value == nullptr) { + return FALSE; } - FlKeyChannelUserData* data = - fl_key_channel_user_data_new(self, callback, user_data); - // Send the message off to the framework for handling (or not). - fl_basic_message_channel_send(self->channel, message, nullptr, - handle_response, data); + *handled = *return_value; + return TRUE; } diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index 66a47d22bd1ac..198fa1b883bc2 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -7,30 +7,6 @@ #include "flutter/shell/platform/linux/fl_key_event.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" - -typedef FlValue* (*FlValueConverter)(FlValue*); - -/** - * FlKeyChannelResponderMock: - * - * Allows mocking of FlKeyChannelResponder methods and values. Only used in - * unittests. - */ -typedef struct _FlKeyChannelResponderMock { - /** - * FlKeyChannelResponderMock::value_converter: - * If #value_converter is not nullptr, then this function is applied to the - * reply of the message, whose return value is taken as the message reply. - */ - FlValueConverter value_converter; - - /** - * FlKeyChannelResponderMock::channel_name: - * Mocks the channel name to send the message. - */ - const char* channel_name; -} FlKeyChannelResponderMock; G_BEGIN_DECLS @@ -40,18 +16,6 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, KEY_CHANNEL_RESPONDER, GObject); -/** - * FlKeyChannelResponderAsyncCallback: - * @event: whether the event has been handled. - * @user_data: the same value as user_data sent by - * #fl_key_responder_handle_event. - * - * The signature for a callback with which a #FlKeyChannelResponder - *asynchronously reports whether the responder handles the event. - **/ -typedef void (*FlKeyChannelResponderAsyncCallback)(bool handled, - gpointer user_data); - /** * FlKeyChannelResponder: * @@ -64,15 +28,13 @@ typedef void (*FlKeyChannelResponderAsyncCallback)(bool handled, /** * fl_key_channel_responder_new: * @messenger: the messenger that the message channel should be built on. - * @mock: options to mock several functionalities. Only used in unittests. * * Creates a new #FlKeyChannelResponder. * * Returns: a new #FlKeyChannelResponder. */ FlKeyChannelResponder* fl_key_channel_responder_new( - FlBinaryMessenger* messenger, - FlKeyChannelResponderMock* mock = nullptr); + FlBinaryMessenger* messenger); /** * fl_key_channel_responder_handle_event: @@ -80,21 +42,37 @@ FlKeyChannelResponder* fl_key_channel_responder_new( * @event: the event to be handled. Must not be null. The object is managed by * callee and must not be assumed available after this function. * @specified_logical_key: - * @callback: the callback to report the result. It should be called exactly - * once. Must not be null. - * @user_data: a value that will be sent back in the callback. Can be null. + * @cancellable: (allow-none): a #GCancellable or %NULL. + * @callback: (scope async): a #GAsyncReadyCallback to call when the event has + * been processed. + * @user_data: (closure): user data to pass to @callback. + * + * Let the responder handle an event. + */ +void fl_key_channel_responder_handle_event(FlKeyChannelResponder* responder, + FlKeyEvent* event, + uint64_t specified_logical_key, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +/** + * fl_key_channel_responder_handle_event_finish: + * @responder: an #FlKeyChannelResponder. + * @result: a #GAsyncResult. + * @handled: location to write if this event was handled by the platform. + * @error: (allow-none): #GError location to store the error occurring, or %NULL + * to ignore. + * + * Completes request started with fl_key_channel_responder_handle_event(). * - * Let the responder handle an event, expecting the responder to report - * whether to handle the event. The result will be reported by invoking - * `callback` exactly once, which might happen after - * `fl_key_channel_responder_handle_event` or during it. + * Returns %TRUE on success. */ -void fl_key_channel_responder_handle_event( +gboolean fl_key_channel_responder_handle_event_finish( FlKeyChannelResponder* responder, - FlKeyEvent* event, - uint64_t specified_logical_key, - FlKeyChannelResponderAsyncCallback callback, - gpointer user_data); + GAsyncResult* result, + gboolean* handled, + GError** error); G_END_DECLS diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 2c68d40b0d12a..62307139232b5 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -7,64 +7,87 @@ #include "gtest/gtest.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" -#include "flutter/shell/platform/linux/fl_engine_private.h" -#include "flutter/shell/platform/linux/testing/fl_test.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" -static const char* expected_value = nullptr; -static gboolean expected_handled = FALSE; +typedef struct { + const gchar* expected_message; + gboolean handled; +} KeyEventData; -static FlValue* echo_response_cb(FlValue* echoed_value) { - gchar* text = fl_value_to_string(echoed_value); - EXPECT_STREQ(text, expected_value); - g_free(text); +static FlValue* key_event_cb(FlMockBinaryMessenger* messenger, + FlValue* message, + gpointer user_data) { + KeyEventData* data = static_cast(user_data); - FlValue* value = fl_value_new_map(); - fl_value_set_string_take(value, "handled", - fl_value_new_bool(expected_handled)); - return value; + g_autofree gchar* message_string = fl_value_to_string(message); + EXPECT_STREQ(message_string, data->expected_message); + + FlValue* response = fl_value_new_map(); + fl_value_set_string_take(response, "handled", + fl_value_new_bool(data->handled)); + + free(data); + + return response; } -static void responder_callback(bool handled, gpointer user_data) { - EXPECT_EQ(handled, expected_handled); - g_main_loop_quit(static_cast(user_data)); +static void set_key_event_channel(FlMockBinaryMessenger* messenger, + const gchar* expected_message, + gboolean handled) { + KeyEventData* data = g_new0(KeyEventData, 1); + data->expected_message = expected_message; + data->handled = handled; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/keyevent", key_event_cb, data); } // Test sending a letter "A"; TEST(FlKeyChannelResponderTest, SendKeyEvent) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", - }; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlKeyChannelResponder) responder = - fl_key_channel_responder_new(messenger, &mock); + fl_key_channel_responder_new(FL_BINARY_MESSENGER(messenger)); + set_key_event_channel( + messenger, + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " + "modifiers: 0, unicodeScalarValues: 65}", + FALSE); g_autoptr(FlKeyEvent) event1 = fl_key_event_new( 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event1, 0, - responder_callback, loop); - expected_value = - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " - "modifiers: 0, unicodeScalarValues: 65}"; - expected_handled = FALSE; - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event1, 0, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + gboolean handled; + EXPECT_TRUE(fl_key_channel_responder_handle_event_finish( + FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr)); + EXPECT_FALSE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + set_key_event_channel( + messenger, + "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " + "modifiers: 0, unicodeScalarValues: 65}", + FALSE); g_autoptr(FlKeyEvent) event2 = fl_key_event_new( 23456, FALSE, 0x04, GDK_KEY_A, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event2, 0, - responder_callback, loop); - expected_value = - "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " - "modifiers: 0, unicodeScalarValues: 65}"; - expected_handled = FALSE; - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event2, 0, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + gboolean handled; + EXPECT_TRUE(fl_key_channel_responder_handle_event_finish( + FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr)); + EXPECT_FALSE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } void test_lock_event(guint key_code, @@ -72,34 +95,41 @@ void test_lock_event(guint key_code, const char* up_expected) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", - }; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlKeyChannelResponder) responder = - fl_key_channel_responder_new(messenger, &mock); + fl_key_channel_responder_new(FL_BINARY_MESSENGER(messenger)); + set_key_event_channel(messenger, down_expected, FALSE); g_autoptr(FlKeyEvent) event1 = fl_key_event_new( 12345, TRUE, 0x04, key_code, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event1, 0, - responder_callback, loop); - expected_value = down_expected; - expected_handled = FALSE; - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event1, 0, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + gboolean handled; + EXPECT_TRUE(fl_key_channel_responder_handle_event_finish( + FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr)); + EXPECT_FALSE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); - expected_value = up_expected; - expected_handled = FALSE; + set_key_event_channel(messenger, up_expected, FALSE); g_autoptr(FlKeyEvent) event2 = fl_key_event_new( 12346, FALSE, 0x04, key_code, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event2, 0, - responder_callback, loop); - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event2, 0, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + gboolean handled; + EXPECT_TRUE(fl_key_channel_responder_handle_event_finish( + FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr)); + EXPECT_FALSE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } // Test sending a "NumLock" keypress. @@ -132,50 +162,58 @@ TEST(FlKeyChannelResponderTest, SendShiftLockKeyEvent) { TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", - }; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlKeyChannelResponder) responder = - fl_key_channel_responder_new(messenger, &mock); + fl_key_channel_responder_new(FL_BINARY_MESSENGER(messenger)); + set_key_event_channel( + messenger, + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65, modifiers: 0, unicodeScalarValues: 65}", + TRUE); g_autoptr(FlKeyEvent) event = fl_key_event_new( 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event, 0, responder_callback, - loop); - expected_handled = TRUE; - expected_value = - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " - "keyCode: 65, modifiers: 0, unicodeScalarValues: 65}"; - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event, 0, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + gboolean handled; + EXPECT_TRUE(fl_key_channel_responder_handle_event_finish( + FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr)); + EXPECT_TRUE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlKeyChannelResponderTest, UseSpecifiedLogicalKey) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", - }; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlKeyChannelResponder) responder = - fl_key_channel_responder_new(messenger, &mock); + fl_key_channel_responder_new(FL_BINARY_MESSENGER(messenger)); - g_autoptr(FlKeyEvent) event = fl_key_event_new( - 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event, 888, - responder_callback, loop); - expected_handled = TRUE; - expected_value = + set_key_event_channel( + messenger, "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " "keyCode: 65, modifiers: 0, unicodeScalarValues: 65, " - "specifiedLogicalKey: 888}"; - - // Blocks here until echo_response_cb is called. + "specifiedLogicalKey: 888}", + TRUE); + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); + fl_key_channel_responder_handle_event( + responder, event, 888, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + gboolean handled; + EXPECT_TRUE(fl_key_channel_responder_handle_event_finish( + FL_KEY_CHANNEL_RESPONDER(object), result, &handled, nullptr)); + EXPECT_TRUE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } diff --git a/shell/platform/linux/fl_key_embedder_responder.h b/shell/platform/linux/fl_key_embedder_responder.h index 1905d4b3fa329..18e1f16ca536d 100644 --- a/shell/platform/linux/fl_key_embedder_responder.h +++ b/shell/platform/linux/fl_key_embedder_responder.h @@ -8,8 +8,6 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/fl_key_event.h" -constexpr int kMaxConvertedKeyData = 3; - // The signature of a function that FlKeyEmbedderResponder calls on every key // event. // diff --git a/shell/platform/linux/fl_key_event_channel.cc b/shell/platform/linux/fl_key_event_channel.cc new file mode 100644 index 0000000000000..bd9fedc9f10f2 --- /dev/null +++ b/shell/platform/linux/fl_key_event_channel.cc @@ -0,0 +1,122 @@ +// 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_key_event_channel.h" + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" + +static constexpr char kChannelName[] = "flutter/keyevent"; +static constexpr char kTypeKey[] = "type"; +static constexpr char kTypeValueUp[] = "keyup"; +static constexpr char kTypeValueDown[] = "keydown"; +static constexpr char kKeymapKey[] = "keymap"; +static constexpr char kKeyCodeKey[] = "keyCode"; +static constexpr char kScanCodeKey[] = "scanCode"; +static constexpr char kModifiersKey[] = "modifiers"; +static constexpr char kToolkitKey[] = "toolkit"; +static constexpr char kSpecifiedLogicalKey[] = "specifiedLogicalKey"; +static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues"; + +static constexpr char kGtkToolkit[] = "gtk"; +static constexpr char kLinuxKeymap[] = "linux"; + +static constexpr int64_t kUnicodeScalarValuesUnset = 0; +static constexpr int64_t kSpecifiedLogicalKeyUnset = 0; + +struct _FlKeyEventChannel { + GObject parent_instance; + + FlBasicMessageChannel* channel; +}; + +G_DEFINE_TYPE(FlKeyEventChannel, fl_key_event_channel, G_TYPE_OBJECT) + +static void fl_key_event_channel_dispose(GObject* object) { + FlKeyEventChannel* self = FL_KEY_EVENT_CHANNEL(object); + + g_clear_object(&self->channel); + + G_OBJECT_CLASS(fl_key_event_channel_parent_class)->dispose(object); +} + +static void fl_key_event_channel_class_init(FlKeyEventChannelClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_event_channel_dispose; +} + +static void fl_key_event_channel_init(FlKeyEventChannel* self) {} + +FlKeyEventChannel* fl_key_event_channel_new(FlBinaryMessenger* messenger) { + g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); + + FlKeyEventChannel* self = FL_KEY_EVENT_CHANNEL( + g_object_new(fl_key_event_channel_get_type(), nullptr)); + + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + self->channel = fl_basic_message_channel_new(messenger, kChannelName, + FL_MESSAGE_CODEC(codec)); + + return self; +} + +void fl_key_event_channel_send(FlKeyEventChannel* self, + FlKeyEventType type, + int64_t scan_code, + int64_t key_code, + int64_t modifiers, + int64_t unicode_scalar_values, + int64_t specified_logical_key, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_KEY_EVENT_CHANNEL(self)); + + const gchar* type_string; + switch (type) { + case FL_KEY_EVENT_TYPE_KEYUP: + type_string = kTypeValueUp; + break; + case FL_KEY_EVENT_TYPE_KEYDOWN: + type_string = kTypeValueDown; + break; + default: + g_assert_not_reached(); + } + + g_autoptr(FlValue) message = fl_value_new_map(); + fl_value_set_string_take(message, kTypeKey, fl_value_new_string(type_string)); + fl_value_set_string_take(message, kKeymapKey, + fl_value_new_string(kLinuxKeymap)); + fl_value_set_string_take(message, kScanCodeKey, fl_value_new_int(scan_code)); + fl_value_set_string_take(message, kToolkitKey, + fl_value_new_string(kGtkToolkit)); + fl_value_set_string_take(message, kKeyCodeKey, fl_value_new_int(key_code)); + fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(modifiers)); + if (unicode_scalar_values != kUnicodeScalarValuesUnset) { + fl_value_set_string_take(message, kUnicodeScalarValuesKey, + fl_value_new_int(unicode_scalar_values)); + } + if (specified_logical_key != kSpecifiedLogicalKeyUnset) { + fl_value_set_string_take(message, kSpecifiedLogicalKey, + fl_value_new_int(specified_logical_key)); + } + fl_basic_message_channel_send(self->channel, message, cancellable, callback, + user_data); +} + +gboolean fl_key_event_channel_send_finish(GObject* object, + GAsyncResult* result, + gboolean* handled, + GError** error) { + g_autoptr(FlValue) message = fl_basic_message_channel_send_finish( + FL_BASIC_MESSAGE_CHANNEL(object), result, error); + if (message == nullptr) { + return FALSE; + } + + FlValue* handled_value = fl_value_lookup_string(message, "handled"); + *handled = fl_value_get_bool(handled_value); + + return TRUE; +} diff --git a/shell/platform/linux/fl_key_event_channel.h b/shell/platform/linux/fl_key_event_channel.h new file mode 100644 index 0000000000000..ae8bd38f12e47 --- /dev/null +++ b/shell/platform/linux/fl_key_event_channel.h @@ -0,0 +1,86 @@ +// 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_KEY_EVENT_CHANNEL_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_CHANNEL_H_ + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlKeyEventChannel, + fl_key_event_channel, + FL, + KEY_EVENT_CHANNEL, + GObject); + +/** + * FlKeyEventChannel: + * + * #FlKeyEventChannel is a channel that implements the shell side + * of SystemChannels.keyEvent from the Flutter services library. + */ + +typedef enum { + FL_KEY_EVENT_TYPE_KEYUP, + FL_KEY_EVENT_TYPE_KEYDOWN, +} FlKeyEventType; + +/** + * fl_key_event_channel_new: + * @messenger: an #FlBinaryMessenger + * + * Creates a new channel that implements SystemChannels.keyEvent from the + * Flutter services library. + * + * Returns: a new #FlKeyEventChannel. + */ +FlKeyEventChannel* fl_key_event_channel_new(FlBinaryMessenger* messenger); + +/** + * fl_key_event_channel_send: + * @channel: an #FlKeyEventChannel + * @type: event type. + * @scan_code: scan code. + * @key_code: key code. + * @modifiers: modifiers. + * @unicode_scarlar_values: + * @specified_logical_key: + * @cancellable: (allow-none): a #GCancellable or %NULL. + * @callback: (scope async): a #GAsyncReadyCallback to call when the method + * returns. + * @user_data: (closure): user data to pass to @callback. + * + * Send a key event to the platform. + */ +void fl_key_event_channel_send(FlKeyEventChannel* channel, + FlKeyEventType type, + int64_t scan_code, + int64_t key_code, + int64_t modifiers, + int64_t unicode_scarlar_values, + int64_t specified_logical_key, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +/** + * fl_key_event_channel_send_finish: + * @object: + * @result: a #GAsyncResult. + * @error: (allow-none): #GError location to store the error occurring, or %NULL + * to ignore. + * + * Completes request started with fl_key_event_channel_send(). + * + * Returns: %TRUE on success. + */ +gboolean fl_key_event_channel_send_finish(GObject* object, + GAsyncResult* result, + gboolean* handled, + GError** error); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_CHANNEL_H_ diff --git a/shell/platform/linux/fl_keyboard_handler_test.cc b/shell/platform/linux/fl_keyboard_handler_test.cc index 26fd103263657..5cb1f6c86b210 100644 --- a/shell/platform/linux/fl_keyboard_handler_test.cc +++ b/shell/platform/linux/fl_keyboard_handler_test.cc @@ -4,9 +4,10 @@ #include "flutter/shell/platform/linux/fl_keyboard_handler.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/public/flutter_linux/fl_standard_method_codec.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -26,19 +27,6 @@ G_DECLARE_FINAL_TYPE(FlMockKeyboardHandlerDelegate, 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; -} - struct _FlMockKeyboardHandlerDelegate { GObject parent_instance; }; @@ -74,8 +62,7 @@ static FlMockKeyboardHandlerDelegate* fl_mock_keyboard_handler_delegate_new() { } TEST(FlKeyboardHandlerTest, KeyboardChannelGetPressedState) { - ::testing::NiceMock messenger; - + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlEngine) engine = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger", FL_BINARY_MESSENGER(messenger), nullptr)); @@ -95,21 +82,28 @@ TEST(FlKeyboardHandlerTest, KeyboardChannelGetPressedState) { }, nullptr); g_autoptr(FlKeyboardHandler) handler = - fl_keyboard_handler_new(messenger, manager); + fl_keyboard_handler_new(FL_BINARY_MESSENGER(messenger), manager); EXPECT_NE(handler, nullptr); - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), kGetKeyboardStateMethod, nullptr, nullptr); - - g_autoptr(FlValue) response = fl_value_new_map(); - fl_value_set_take(response, fl_value_new_int(kMockPhysicalKey), - fl_value_new_int(kMockLogicalKey)); - EXPECT_CALL(messenger, - fl_binary_messenger_send_response( - ::testing::Eq(messenger), ::testing::_, - MethodSuccessResponse(response), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_standard_method( + messenger, kKeyboardChannelName, kGetKeyboardStateMethod, nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_map(); + fl_value_set_take(expected_result, fl_value_new_int(kMockPhysicalKey), + fl_value_new_int(kMockLogicalKey)); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); - messenger.ReceiveMessage(kKeyboardChannelName, message); + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index defbe022c1f03..0a4925737a750 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -21,10 +21,10 @@ /* Declarations of private classes */ -G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData, - fl_keyboard_manager_user_data, +G_DECLARE_FINAL_TYPE(FlKeyboardManagerData, + fl_keyboard_manager_data, FL, - KEYBOARD_MANAGER_USER_DATA, + KEYBOARD_MANAGER_DATA, GObject); /* End declarations */ @@ -62,52 +62,50 @@ void debug_format_layout_data(std::string& debug_layout_data, } // namespace -/* Define FlKeyboardManagerUserData */ +/* Define FlKeyboardManagerData */ /** - * FlKeyboardManagerUserData: + * FlKeyboardManagerData: * The user_data used when #FlKeyboardManager sends event to * responders. */ -struct _FlKeyboardManagerUserData { +struct _FlKeyboardManagerData { GObject parent_instance; // The owner manager. GWeakRef manager; - uint64_t sequence_id; + + FlKeyboardPendingEvent* pending; }; -G_DEFINE_TYPE(FlKeyboardManagerUserData, - fl_keyboard_manager_user_data, - G_TYPE_OBJECT) +G_DEFINE_TYPE(FlKeyboardManagerData, fl_keyboard_manager_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); +static void fl_keyboard_manager_data_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER_DATA(object)); + FlKeyboardManagerData* self = FL_KEYBOARD_MANAGER_DATA(object); g_weak_ref_clear(&self->manager); - G_OBJECT_CLASS(fl_keyboard_manager_user_data_parent_class)->dispose(object); + G_OBJECT_CLASS(fl_keyboard_manager_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_data_class_init( + FlKeyboardManagerDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_data_dispose; } -static void fl_keyboard_manager_user_data_init( - FlKeyboardManagerUserData* self) {} +static void fl_keyboard_manager_data_init(FlKeyboardManagerData* self) {} -// Creates a new FlKeyboardManagerUserData private class with all information. -static FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new( +// Creates a new FlKeyboardManagerData private class with all information. +static FlKeyboardManagerData* fl_keyboard_manager_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)); + FlKeyboardPendingEvent* pending) { + FlKeyboardManagerData* self = FL_KEYBOARD_MANAGER_DATA( + g_object_new(fl_keyboard_manager_data_get_type(), nullptr)); g_weak_ref_init(&self->manager, manager); - self->sequence_id = sequence_id; + self->pending = FL_KEYBOARD_PENDING_EVENT(g_object_ref(pending)); return self; } @@ -148,9 +146,6 @@ struct _FlKeyboardManager { // 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, @@ -172,6 +167,8 @@ struct _FlKeyboardManager { GdkKeymap* keymap; gulong keymap_keys_changed_cb_id; // Signal connection ID for // keymap-keys-changed + + GCancellable* cancellable; }; G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT); @@ -205,15 +202,6 @@ static gboolean g_ptr_array_find_with_equal_func1(GPtrArray* haystack, 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(a)); - uint64_t sequence_id = *reinterpret_cast(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 = @@ -242,50 +230,23 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, } // The callback used by a responder after the event was dispatched. -static void responder_handle_event_callback(bool handled, - gpointer user_data_ptr, - gboolean is_embedder) { - 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; - } - +static void responder_handle_event_callback(FlKeyboardManager* self, + FlKeyboardPendingEvent* pending) { 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); - if (is_embedder) { - fl_keyboard_pending_event_mark_embedder_replied(pending, handled); - } else { - fl_keyboard_pending_event_mark_channel_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); + g_ptr_array_remove(self->pending_responds, 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); + g_ptr_array_add(self->pending_redispatches, g_object_ref(pending)); FlKeyEvent* event = fl_keyboard_pending_event_get_event(pending); if (self->redispatch_handler != nullptr) { self->redispatch_handler(event, self->redispatch_handler_user_data); @@ -296,20 +257,49 @@ static void responder_handle_event_callback(bool handled, event_type == GDK_KEY_RELEASE); gdk_event_put(fl_key_event_get_origin(event)); } - } else { - g_object_unref(pending); } } } static void responder_handle_embedder_event_callback(bool handled, - gpointer user_data_ptr) { - responder_handle_event_callback(handled, user_data_ptr, TRUE); + gpointer user_data) { + g_autoptr(FlKeyboardManagerData) data = FL_KEYBOARD_MANAGER_DATA(user_data); + + fl_keyboard_pending_event_mark_embedder_replied(data->pending, handled); + + g_autoptr(FlKeyboardManager) self = + FL_KEYBOARD_MANAGER(g_weak_ref_get(&data->manager)); + if (self == nullptr) { + return; + } + + responder_handle_event_callback(self, data->pending); } -static void responder_handle_channel_event_callback(bool handled, - gpointer user_data_ptr) { - responder_handle_event_callback(handled, user_data_ptr, FALSE); +static void responder_handle_channel_event_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(FlKeyboardManagerData) data = FL_KEYBOARD_MANAGER_DATA(user_data); + + g_autoptr(GError) error = nullptr; + gboolean handled; + if (!fl_key_channel_responder_handle_event_finish( + FL_KEY_CHANNEL_RESPONDER(object), result, &handled, &error)) { + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_warning("Failed to handle key event in platform: %s", error->message); + } + return; + } + + g_autoptr(FlKeyboardManager) self = + FL_KEYBOARD_MANAGER(g_weak_ref_get(&data->manager)); + if (self == nullptr) { + return; + } + + fl_keyboard_pending_event_mark_channel_replied(data->pending, handled); + + responder_handle_event_callback(self, data->pending); } static uint16_t convert_key_to_char(FlKeyboardManager* self, @@ -418,6 +408,8 @@ static void guarantee_layout(FlKeyboardManager* self, FlKeyEvent* event) { static void fl_keyboard_manager_dispose(GObject* object) { FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object); + g_cancellable_cancel(self->cancellable); + g_weak_ref_clear(&self->engine); g_weak_ref_clear(&self->view_delegate); @@ -434,6 +426,7 @@ static void fl_keyboard_manager_dispose(GObject* object) { g_signal_handler_disconnect(self->keymap, self->keymap_keys_changed_cb_id); self->keymap_keys_changed_cb_id = 0; } + g_clear_object(&self->cancellable); G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object); } @@ -459,11 +452,10 @@ static void fl_keyboard_manager_init(FlKeyboardManager* self) { 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; - self->keymap = gdk_keymap_get_for_display(gdk_display_get_default()); self->keymap_keys_changed_cb_id = g_signal_connect_swapped( self->keymap, "keys-changed", G_CALLBACK(keymap_keys_changed_cb), self); + self->cancellable = g_cancellable_new(); } FlKeyboardManager* fl_keyboard_manager_new( @@ -511,21 +503,20 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, return FALSE; } - FlKeyboardPendingEvent* pending = - fl_keyboard_pending_event_new(event, ++self->last_sequence_id); + FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new(event); 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)); + g_autoptr(FlKeyboardManagerData) data = + fl_keyboard_manager_data_new(self, 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)); fl_key_embedder_responder_handle_event( self->key_embedder_responder, event, specified_logical_key, - responder_handle_embedder_event_callback, user_data); + responder_handle_embedder_event_callback, g_object_ref(data)); fl_key_channel_responder_handle_event( self->key_channel_responder, event, specified_logical_key, - responder_handle_channel_event_callback, user_data); + self->cancellable, responder_handle_channel_event_cb, g_object_ref(data)); return TRUE; } diff --git a/shell/platform/linux/fl_keyboard_pending_event.cc b/shell/platform/linux/fl_keyboard_pending_event.cc index 7b19cca9fcdb7..5a24ae85ac439 100644 --- a/shell/platform/linux/fl_keyboard_pending_event.cc +++ b/shell/platform/linux/fl_keyboard_pending_event.cc @@ -19,9 +19,6 @@ struct _FlKeyboardPendingEvent { // The target event. FlKeyEvent* event; - // Unique ID to identify pending responds. - uint64_t sequence_id; - // True if the embedder responder has replied. bool embedder_replied; @@ -58,13 +55,11 @@ static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {} // Creates a new FlKeyboardPendingEvent by providing the target event, // the sequence ID, and the number of responders that will reply. -FlKeyboardPendingEvent* fl_keyboard_pending_event_new(FlKeyEvent* event, - uint64_t sequence_id) { +FlKeyboardPendingEvent* fl_keyboard_pending_event_new(FlKeyEvent* event) { FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT( g_object_new(fl_keyboard_pending_event_get_type(), nullptr)); self->event = FL_KEY_EVENT(g_object_ref(event)); - self->sequence_id = sequence_id; self->hash = fl_key_event_hash(self->event); return self; @@ -75,12 +70,6 @@ FlKeyEvent* fl_keyboard_pending_event_get_event(FlKeyboardPendingEvent* self) { return self->event; } -uint64_t fl_keyboard_pending_event_get_sequence_id( - FlKeyboardPendingEvent* self) { - g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), 0); - return self->sequence_id; -} - uint64_t fl_keyboard_pending_event_get_hash(FlKeyboardPendingEvent* self) { g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), 0); return self->hash; diff --git a/shell/platform/linux/fl_keyboard_pending_event.h b/shell/platform/linux/fl_keyboard_pending_event.h index e419598d17147..31827c3c76bdf 100644 --- a/shell/platform/linux/fl_keyboard_pending_event.h +++ b/shell/platform/linux/fl_keyboard_pending_event.h @@ -15,14 +15,10 @@ G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, KEYBOARD_PENDING_EVENT, GObject); -FlKeyboardPendingEvent* fl_keyboard_pending_event_new(FlKeyEvent* event, - uint64_t sequence_id); +FlKeyboardPendingEvent* fl_keyboard_pending_event_new(FlKeyEvent* event); FlKeyEvent* fl_keyboard_pending_event_get_event(FlKeyboardPendingEvent* event); -uint64_t fl_keyboard_pending_event_get_sequence_id( - FlKeyboardPendingEvent* event); - uint64_t fl_keyboard_pending_event_get_hash(FlKeyboardPendingEvent* event); void fl_keyboard_pending_event_mark_embedder_replied( diff --git a/shell/platform/linux/fl_method_channel.cc b/shell/platform/linux/fl_method_channel.cc index 266bfa7d812d7..1fe5277e0866f 100644 --- a/shell/platform/linux/fl_method_channel.cc +++ b/shell/platform/linux/fl_method_channel.cc @@ -63,8 +63,8 @@ static void message_cb(FlBinaryMessenger* messenger, static void message_response_cb(GObject* object, GAsyncResult* result, gpointer user_data) { - GTask* task = G_TASK(user_data); - g_task_return_pointer(task, result, g_object_unref); + g_autoptr(GTask) task = G_TASK(user_data); + g_task_return_pointer(task, g_object_ref(result), g_object_unref); } // Called when the channel handler is closed. @@ -178,7 +178,7 @@ G_MODULE_EXPORT void fl_method_channel_invoke_method( fl_method_codec_encode_method_call(self->codec, method, args, &error); if (message == nullptr) { if (task != nullptr) { - g_task_return_error(task, error); + g_task_return_error(task, g_error_copy(error)); } return; } @@ -196,8 +196,12 @@ G_MODULE_EXPORT FlMethodResponse* fl_method_channel_invoke_method_finish( g_return_val_if_fail(FL_IS_METHOD_CHANNEL(self), nullptr); g_return_val_if_fail(g_task_is_valid(result, self), nullptr); - g_autoptr(GTask) task = G_TASK(result); - GAsyncResult* r = G_ASYNC_RESULT(g_task_propagate_pointer(task, nullptr)); + GTask* task = G_TASK(result); + g_autoptr(GAsyncResult) r = + G_ASYNC_RESULT(g_task_propagate_pointer(task, error)); + if (r == nullptr) { + return nullptr; + } g_autoptr(GBytes) response = fl_binary_messenger_send_on_channel_finish(self->messenger, r, error); @@ -216,34 +220,13 @@ gboolean fl_method_channel_respond( g_return_val_if_fail(FL_IS_METHOD_CHANNEL(self), FALSE); g_return_val_if_fail(FL_IS_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle), FALSE); - g_return_val_if_fail(FL_IS_METHOD_SUCCESS_RESPONSE(response) || - FL_IS_METHOD_ERROR_RESPONSE(response) || - FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response), - FALSE); + g_return_val_if_fail(FL_IS_METHOD_RESPONSE(response), FALSE); - g_autoptr(GBytes) message = nullptr; - if (FL_IS_METHOD_SUCCESS_RESPONSE(response)) { - FlMethodSuccessResponse* r = FL_METHOD_SUCCESS_RESPONSE(response); - message = fl_method_codec_encode_success_envelope( - self->codec, fl_method_success_response_get_result(r), error); - if (message == nullptr) { - return FALSE; - } - } else if (FL_IS_METHOD_ERROR_RESPONSE(response)) { - FlMethodErrorResponse* r = FL_METHOD_ERROR_RESPONSE(response); - message = fl_method_codec_encode_error_envelope( - self->codec, fl_method_error_response_get_code(r), - fl_method_error_response_get_message(r), - fl_method_error_response_get_details(r), error); - if (message == nullptr) { - return FALSE; - } - } else if (FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response)) { - message = nullptr; - } else { - g_assert_not_reached(); + g_autoptr(GBytes) message = + fl_method_codec_encode_response(self->codec, response, error); + if (message == nullptr) { + return FALSE; } - return fl_binary_messenger_send_response(self->messenger, response_handle, message, error); } diff --git a/shell/platform/linux/fl_method_channel_test.cc b/shell/platform/linux/fl_method_channel_test.cc index 7aa0c6572cd0f..c7d366cfde60b 100644 --- a/shell/platform/linux/fl_method_channel_test.cc +++ b/shell/platform/linux/fl_method_channel_test.cc @@ -744,3 +744,36 @@ TEST(FlMethodChannelTest, DisposeAReplacedMethodChannel) { EXPECT_EQ(user_data1.count, 101); EXPECT_EQ(user_data2.count, 102); } + +// Called when the method call response is received in the CustomType +// test. +static void custom_type_response_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish( + FL_METHOD_CHANNEL(object), result, &error); + EXPECT_EQ(response, nullptr); + EXPECT_NE(error, nullptr); + EXPECT_STREQ(error->message, "Custom value not implemented"); + + g_main_loop_quit(static_cast(user_data)); +} + +// Checks invoking a method with a custom type generates an error. +TEST(FlMethodChannelTest, CustomType) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodChannel) channel = fl_method_channel_new( + messenger, "test/standard-method", FL_METHOD_CODEC(codec)); + + g_autoptr(FlValue) args = fl_value_new_custom(42, nullptr, nullptr); + fl_method_channel_invoke_method(channel, "Echo", args, nullptr, + custom_type_response_cb, loop); + + // Blocks here until custom_type_response_cb is called. + g_main_loop_run(loop); +} diff --git a/shell/platform/linux/fl_method_codec.cc b/shell/platform/linux/fl_method_codec.cc index 5b6d87c47a39a..a0c023ca759c3 100644 --- a/shell/platform/linux/fl_method_codec.cc +++ b/shell/platform/linux/fl_method_codec.cc @@ -59,6 +59,32 @@ GBytes* fl_method_codec_encode_error_envelope(FlMethodCodec* self, self, code, message, details, error); } +GBytes* fl_method_codec_encode_response(FlMethodCodec* self, + FlMethodResponse* response, + GError** error) { + g_return_val_if_fail(FL_IS_METHOD_CODEC(self), nullptr); + g_return_val_if_fail(FL_IS_METHOD_SUCCESS_RESPONSE(response) || + FL_IS_METHOD_ERROR_RESPONSE(response) || + FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response), + nullptr); + + if (FL_IS_METHOD_SUCCESS_RESPONSE(response)) { + FlMethodSuccessResponse* r = FL_METHOD_SUCCESS_RESPONSE(response); + return fl_method_codec_encode_success_envelope( + self, fl_method_success_response_get_result(r), error); + } else if (FL_IS_METHOD_ERROR_RESPONSE(response)) { + FlMethodErrorResponse* r = FL_METHOD_ERROR_RESPONSE(response); + return fl_method_codec_encode_error_envelope( + self, fl_method_error_response_get_code(r), + fl_method_error_response_get_message(r), + fl_method_error_response_get_details(r), error); + } else if (FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response)) { + return g_bytes_new(nullptr, 0); + } else { + g_assert_not_reached(); + } +} + FlMethodResponse* fl_method_codec_decode_response(FlMethodCodec* self, GBytes* message, GError** error) { diff --git a/shell/platform/linux/fl_method_codec_private.h b/shell/platform/linux/fl_method_codec_private.h index 8912093adc29c..1880b09cd0983 100644 --- a/shell/platform/linux/fl_method_codec_private.h +++ b/shell/platform/linux/fl_method_codec_private.h @@ -85,6 +85,21 @@ GBytes* fl_method_codec_encode_error_envelope(FlMethodCodec* codec, FlValue* details, GError** error); +/** + * fl_method_codec_encode_response: + * @codec: an #FlMethodCodec. + * @response: response to encode. + * @error: (allow-none): #GError location to store the error occurring, or + * %NULL. + * + * Encodes a response to a method call. + * + * Returns: a new #FlMethodResponse or %NULL on error. + */ +GBytes* fl_method_codec_encode_response(FlMethodCodec* codec, + FlMethodResponse* response, + GError** error); + /** * fl_method_codec_decode_response: * @codec: an #FlMethodCodec. @@ -92,8 +107,7 @@ GBytes* fl_method_codec_encode_error_envelope(FlMethodCodec* codec, * @error: (allow-none): #GError location to store the error occurring, or * %NULL. * - * Decodes a response to a method call. If the call resulted in an error then - * @error_code is set, otherwise it is %NULL. + * Decodes a response to a method call. * * Returns: a new #FlMethodResponse or %NULL on error. */ diff --git a/shell/platform/linux/fl_platform_channel.cc b/shell/platform/linux/fl_platform_channel.cc index 3e45f03cd9ea5..cd5fb904d5062 100644 --- a/shell/platform/linux/fl_platform_channel.cc +++ b/shell/platform/linux/fl_platform_channel.cc @@ -110,7 +110,7 @@ FlPlatformChannelExitResponse get_exit_response(FlMethodResponse* response) { if (strcmp(response_string, kExitResponseCancel) == 0) { return FL_PLATFORM_CHANNEL_EXIT_RESPONSE_CANCEL; } else if (strcmp(response_string, kExitResponseExit) == 0) { - return FL_PLATFORM_CHANNEL_EXIT_RESPONSE_CANCEL; + return FL_PLATFORM_CHANNEL_EXIT_RESPONSE_EXIT; } // If something went wrong, then just exit. diff --git a/shell/platform/linux/fl_platform_channel_test.cc b/shell/platform/linux/fl_platform_channel_test.cc new file mode 100644 index 0000000000000..45aeeef2a0531 --- /dev/null +++ b/shell/platform/linux/fl_platform_channel_test.cc @@ -0,0 +1,43 @@ +// 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_platform_channel.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.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" +#include "flutter/shell/platform/linux/testing/fl_test.h" +#include "gtest/gtest.h" + +static void exit_method_response_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + FlPlatformChannelExitResponse response; + gboolean success = fl_platform_channel_system_request_app_exit_finish( + object, result, &response, &error); + + EXPECT_TRUE(success); + EXPECT_EQ(response, FL_PLATFORM_CHANNEL_EXIT_RESPONSE_EXIT); + + g_main_loop_quit(static_cast(user_data)); +} + +TEST(FlPlatformChannelTest, ExitResponse) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodChannel) channel = fl_method_channel_new( + messenger, "test/standard-method", FL_METHOD_CODEC(codec)); + + g_autoptr(FlValue) args = fl_value_new_map(); + fl_value_set_string_take(args, "response", fl_value_new_string("exit")); + + fl_method_channel_invoke_method(channel, "Echo", args, nullptr, + exit_method_response_cb, loop); + + // Blocks here until method_response_cb is called. + g_main_loop_run(loop); +} diff --git a/shell/platform/linux/fl_platform_handler_test.cc b/shell/platform/linux/fl_platform_handler_test.cc index 98369d227beff..4de202e1eb047 100644 --- a/shell/platform/linux/fl_platform_handler_test.cc +++ b/shell/platform/linux/fl_platform_handler_test.cc @@ -5,90 +5,14 @@ #include #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/fl_platform_handler.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" -#include "flutter/testing/testing.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -MATCHER_P(SuccessResponse, result, "") { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); - if (fl_value_equal(fl_method_response_get_result(response, nullptr), - result)) { - return true; - } - *result_listener << ::testing::PrintToString(response); - return false; -} - -class MethodCallMatcher { - public: - using is_gtest_matcher = void; - - explicit MethodCallMatcher(::testing::Matcher name, - ::testing::Matcher args) - : name_(std::move(name)), args_(std::move(args)) {} - - bool MatchAndExplain(GBytes* method_call, - ::testing::MatchResultListener* result_listener) const { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autofree gchar* name = nullptr; - g_autoptr(FlValue) args = nullptr; - gboolean result = fl_method_codec_decode_method_call( - FL_METHOD_CODEC(codec), method_call, &name, &args, &error); - if (!result) { - *result_listener << ::testing::PrintToString(error->message); - return false; - } - if (!name_.MatchAndExplain(name, result_listener)) { - *result_listener << " where the name doesn't match: \"" << name << "\""; - return false; - } - if (!args_.MatchAndExplain(args, result_listener)) { - *result_listener << " where the args don't match: " - << ::testing::PrintToString(args); - return false; - } - return true; - } - - void DescribeTo(std::ostream* os) const { - *os << "method name "; - name_.DescribeTo(os); - *os << " and args "; - args_.DescribeTo(os); - } - - void DescribeNegationTo(std::ostream* os) const { - *os << "method name "; - name_.DescribeNegationTo(os); - *os << " or args "; - args_.DescribeNegationTo(os); - } - - private: - ::testing::Matcher name_; - ::testing::Matcher args_; -}; - -static ::testing::Matcher MethodCall( - const std::string& name, - ::testing::Matcher args) { - return MethodCallMatcher(::testing::StrEq(name), std::move(args)); -} - -MATCHER_P(FlValueEq, value, "equal to " + ::testing::PrintToString(value)) { - return fl_value_equal(arg, value); -} - G_DECLARE_FINAL_TYPE(FlTestApplication, fl_test_application, FL, @@ -116,26 +40,35 @@ static void fl_test_application_startup(GApplication* application) { static void fl_test_application_activate(GApplication* application) { G_APPLICATION_CLASS(fl_test_application_parent_class)->activate(application); - ::testing::NiceMock messenger; - g_autoptr(FlPlatformHandler) handler = fl_platform_handler_new(messenger); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + g_autoptr(FlPlatformHandler) handler = + fl_platform_handler_new(FL_BINARY_MESSENGER(messenger)); EXPECT_NE(handler, nullptr); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - - g_autoptr(FlValue) exit_result = fl_value_new_map(); - fl_value_set_string_take(exit_result, "response", - fl_value_new_string("exit")); - EXPECT_CALL(messenger, - fl_binary_messenger_send_response( - ::testing::Eq(messenger), ::testing::_, - SuccessResponse(exit_result), ::testing::_)) - .WillOnce(::testing::Return(true)); // Request app exit. + gboolean called = FALSE; g_autoptr(FlValue) args = fl_value_new_map(); fl_value_set_string_take(args, "type", fl_value_new_string("required")); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "System.exitApplication", args, nullptr); - messenger.ReceiveMessage("flutter/platform", message); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/platform", "System.exitApplication", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_map(); + fl_value_set_string_take(expected_result, "response", + fl_value_new_string("exit")); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } static void fl_test_application_dispose(GObject* object) { @@ -171,59 +104,107 @@ FlTestApplication* fl_test_application_new(gboolean* dispose_called) { } TEST(FlPlatformHandlerTest, PlaySound) { - ::testing::NiceMock messenger; - - g_autoptr(FlPlatformHandler) handler = fl_platform_handler_new(messenger); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + g_autoptr(FlPlatformHandler) handler = + fl_platform_handler_new(FL_BINARY_MESSENGER(messenger)); EXPECT_NE(handler, nullptr); + gboolean called = FALSE; g_autoptr(FlValue) args = fl_value_new_string("SystemSoundType.alert"); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "SystemSound.play", args, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/platform", message); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/platform", "SystemSound.play", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlPlatformHandlerTest, ExitApplication) { - ::testing::NiceMock messenger; + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(FlPlatformHandler) handler = fl_platform_handler_new(messenger); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + g_autoptr(FlPlatformHandler) handler = + fl_platform_handler_new(FL_BINARY_MESSENGER(messenger)); EXPECT_NE(handler, nullptr); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - - g_autoptr(FlValue) null = fl_value_new_null(); - ON_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillByDefault(testing::Return(TRUE)); // Indicate that the binding is initialized. - g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) init_message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "System.initializationComplete", nullptr, &error); - messenger.ReceiveMessage("flutter/platform", init_message); - - g_autoptr(FlValue) request_args = fl_value_new_map(); - fl_value_set_string_take(request_args, "type", - fl_value_new_string("cancelable")); - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/platform"), - MethodCall("System.requestAppExit", FlValueEq(request_args)), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/platform", "System.initializationComplete", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + gboolean request_exit_called = FALSE; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/platform", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_STREQ(name, "System.requestAppExit"); + + g_autoptr(FlValue) expected_args = fl_value_new_map(); + fl_value_set_string_take(expected_args, "type", + fl_value_new_string("cancelable")); + EXPECT_TRUE(fl_value_equal(args, expected_args)); + + // Cancel so it doesn't try and exit this app (i.e. the current test) + g_autoptr(FlValue) result = fl_value_new_map(); + fl_value_set_string_take(result, "response", + fl_value_new_string("cancel")); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); + }, + &request_exit_called); g_autoptr(FlValue) args = fl_value_new_map(); fl_value_set_string_take(args, "type", fl_value_new_string("cancelable")); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "System.exitApplication", args, nullptr); - messenger.ReceiveMessage("flutter/platform", message); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/platform", "System.exitApplication", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_map(); + fl_value_set_string_take(expected_result, "response", + fl_value_new_string("cancel")); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + + g_main_loop_quit(static_cast(user_data)); + }, + loop); + + g_main_loop_run(loop); + + EXPECT_TRUE(request_exit_called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlPlatformHandlerTest, ExitApplicationDispose) { diff --git a/shell/platform/linux/fl_renderer.cc b/shell/platform/linux/fl_renderer.cc index 63e0a8186ba60..2465390a2951a 100644 --- a/shell/platform/linux/fl_renderer.cc +++ b/shell/platform/linux/fl_renderer.cc @@ -89,6 +89,12 @@ static gboolean is_nvidia() { return strstr(vendor, "NVIDIA") != nullptr; } +// Check if running on an Vivante Corporation driver. +static gboolean is_vivante() { + const gchar* vendor = reinterpret_cast(glGetString(GL_VENDOR)); + return strstr(vendor, "Vivante Corporation") != nullptr; +} + // Returns the log for the given OpenGL shader. Must be freed by the caller. static gchar* get_shader_log(GLuint shader) { GLint log_length; @@ -568,11 +574,12 @@ void fl_renderer_setup(FlRenderer* self) { g_return_if_fail(FL_IS_RENDERER(self)); - // Note: NVIDIA is temporarily disabled due to + // Note: NVIDIA and Vivante are temporarily disabled due to // https://github.com/flutter/flutter/issues/152099 priv->has_gl_framebuffer_blit = - !is_nvidia() && (epoxy_gl_version() >= 30 || - epoxy_has_gl_extension("GL_EXT_framebuffer_blit")); + !is_nvidia() && !is_vivante() && + (epoxy_gl_version() >= 30 || + epoxy_has_gl_extension("GL_EXT_framebuffer_blit")); if (!priv->has_gl_framebuffer_blit) { setup_shader(self); diff --git a/shell/platform/linux/fl_settings_handler_test.cc b/shell/platform/linux/fl_settings_handler_test.cc index 3bffcc2f23313..e8ebd34934100 100644 --- a/shell/platform/linux/fl_settings_handler_test.cc +++ b/shell/platform/linux/fl_settings_handler_test.cc @@ -5,114 +5,187 @@ #include "flutter/shell/platform/linux/fl_settings_handler.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_engine_private.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.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_settings.h" #include "flutter/testing/testing.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -MATCHER_P2(HasSetting, key, value, "") { - g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - g_autoptr(FlValue) message = - fl_message_codec_decode_message(FL_MESSAGE_CODEC(codec), arg, nullptr); - if (fl_value_equal(fl_value_lookup_string(message, key), value)) { - return true; - } - *result_listener << ::testing::PrintToString(message); - return false; -} - -#define EXPECT_SETTING(messenger, key, value) \ - EXPECT_CALL( \ - messenger, \ - fl_binary_messenger_send_on_channel( \ - ::testing::Eq(messenger), \ - ::testing::StrEq("flutter/settings"), HasSetting(key, value), \ - ::testing::A(), ::testing::A(), \ - ::testing::A())) - TEST(FlSettingsHandlerTest, AlwaysUse24HourFormat) { ::testing::NiceMock settings; - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlEngine) engine = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger", FL_BINARY_MESSENGER(messenger), nullptr)); g_autoptr(FlSettingsHandler) handler = fl_settings_handler_new(engine); - g_autoptr(FlValue) use_12h = fl_value_new_bool(false); - g_autoptr(FlValue) use_24h = fl_value_new_bool(true); - EXPECT_CALL(settings, fl_settings_get_clock_format( ::testing::Eq(settings))) .WillOnce(::testing::Return(FL_CLOCK_FORMAT_12H)) .WillOnce(::testing::Return(FL_CLOCK_FORMAT_24H)); - EXPECT_SETTING(messenger, "alwaysUse24HourFormat", use_12h); - + gboolean called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = + fl_value_lookup_string(message, "alwaysUse24HourFormat"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_BOOL); + EXPECT_FALSE(fl_value_get_bool(value)); + + return fl_value_new_null(); + }, + &called); fl_settings_handler_start(handler, settings); - - EXPECT_SETTING(messenger, "alwaysUse24HourFormat", use_24h); - + EXPECT_TRUE(called); + + called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = + fl_value_lookup_string(message, "alwaysUse24HourFormat"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_BOOL); + EXPECT_TRUE(fl_value_get_bool(value)); + + return fl_value_new_null(); + }, + &called); fl_settings_emit_changed(settings); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlSettingsHandlerTest, PlatformBrightness) { ::testing::NiceMock settings; - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlEngine) engine = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger", FL_BINARY_MESSENGER(messenger), nullptr)); g_autoptr(FlSettingsHandler) handler = fl_settings_handler_new(engine); - g_autoptr(FlValue) light = fl_value_new_string("light"); - g_autoptr(FlValue) dark = fl_value_new_string("dark"); - EXPECT_CALL(settings, fl_settings_get_color_scheme( ::testing::Eq(settings))) .WillOnce(::testing::Return(FL_COLOR_SCHEME_LIGHT)) .WillOnce(::testing::Return(FL_COLOR_SCHEME_DARK)); - EXPECT_SETTING(messenger, "platformBrightness", light); - + gboolean called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = fl_value_lookup_string(message, "platformBrightness"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), "light"); + + return fl_value_new_null(); + }, + &called); fl_settings_handler_start(handler, settings); - - EXPECT_SETTING(messenger, "platformBrightness", dark); - + EXPECT_TRUE(called); + + called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = fl_value_lookup_string(message, "platformBrightness"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), "dark"); + + return fl_value_new_null(); + }, + &called); fl_settings_emit_changed(settings); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlSettingsHandlerTest, TextScaleFactor) { ::testing::NiceMock settings; - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlEngine) engine = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger", FL_BINARY_MESSENGER(messenger), nullptr)); g_autoptr(FlSettingsHandler) handler = fl_settings_handler_new(engine); - g_autoptr(FlValue) one = fl_value_new_float(1.0); - g_autoptr(FlValue) two = fl_value_new_float(2.0); - EXPECT_CALL(settings, fl_settings_get_text_scaling_factor( ::testing::Eq(settings))) .WillOnce(::testing::Return(1.0)) .WillOnce(::testing::Return(2.0)); - EXPECT_SETTING(messenger, "textScaleFactor", one); - + gboolean called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = fl_value_lookup_string(message, "textScaleFactor"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_float(value), 1.0); + + return fl_value_new_null(); + }, + &called); fl_settings_handler_start(handler, settings); - - EXPECT_SETTING(messenger, "textScaleFactor", two); - + EXPECT_TRUE(called); + + called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = fl_value_lookup_string(message, "textScaleFactor"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_float(value), 2.0); + + return fl_value_new_null(); + }, + &called); fl_settings_emit_changed(settings); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } // MOCK_ENGINE_PROC is leaky by design diff --git a/shell/platform/linux/fl_text_input_handler_test.cc b/shell/platform/linux/fl_text_input_handler_test.cc index 7787b422c3c6c..a124b236ff3c0 100644 --- a/shell/platform/linux/fl_text_input_handler_test.cc +++ b/shell/platform/linux/fl_text_input_handler_test.cc @@ -4,14 +4,11 @@ #include +#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/fl_text_input_handler.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.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_binary_messenger_response_handle.h" #include "flutter/shell/platform/linux/testing/mock_im_context.h" #include "flutter/shell/platform/linux/testing/mock_text_input_view_delegate.h" #include "flutter/testing/testing.h" @@ -19,83 +16,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -void printTo(FlMethodResponse* response, ::std::ostream* os) { - *os << ::testing::PrintToString( - fl_method_response_get_result(response, nullptr)); -} - -MATCHER_P(SuccessResponse, result, "") { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); - if (fl_value_equal(fl_method_response_get_result(response, nullptr), - result)) { - return true; - } - *result_listener << ::testing::PrintToString(response); - return false; -} - -MATCHER_P(FlValueEq, value, "equal to " + ::testing::PrintToString(value)) { - return fl_value_equal(arg, value); -} - -class MethodCallMatcher { - public: - using is_gtest_matcher = void; - - explicit MethodCallMatcher(::testing::Matcher name, - ::testing::Matcher args) - : name_(std::move(name)), args_(std::move(args)) {} - - bool MatchAndExplain(GBytes* method_call, - ::testing::MatchResultListener* result_listener) const { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autofree gchar* name = nullptr; - g_autoptr(FlValue) args = nullptr; - gboolean result = fl_method_codec_decode_method_call( - FL_METHOD_CODEC(codec), method_call, &name, &args, &error); - if (!result) { - *result_listener << ::testing::PrintToString(error->message); - return false; - } - if (!name_.MatchAndExplain(name, result_listener)) { - *result_listener << " where the name doesn't match: \"" << name << "\""; - return false; - } - if (!args_.MatchAndExplain(args, result_listener)) { - *result_listener << " where the args don't match: " - << ::testing::PrintToString(args); - return false; - } - return true; - } - - void DescribeTo(std::ostream* os) const { - *os << "method name "; - name_.DescribeTo(os); - *os << " and args "; - args_.DescribeTo(os); - } - - void DescribeNegationTo(std::ostream* os) const { - *os << "method name "; - name_.DescribeNegationTo(os); - *os << " or args "; - args_.DescribeNegationTo(os); - } - - private: - ::testing::Matcher name_; - ::testing::Matcher args_; -}; - -::testing::Matcher MethodCall(const std::string& name, - ::testing::Matcher args) { - return MethodCallMatcher(::testing::StrEq(name), std::move(args)); -} - static FlValue* build_map(std::map args) { FlValue* value = fl_value_new_map(); for (auto it = args.begin(); it != args.end(); ++it) { @@ -178,6 +98,49 @@ static FlValue* build_editing_delta(EditingDelta delta) { }); } +static void set_client(FlMockBinaryMessenger* messenger, InputConfig config) { + gboolean called = FALSE; + g_autoptr(FlValue) args = build_input_config(config); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.setClient", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); +} + +static void set_editing_state(FlMockBinaryMessenger* messenger, + EditingState state) { + gboolean called = FALSE; + g_autoptr(FlValue) args = build_editing_state(state); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.setEditingState", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); +} + static void send_key_event(FlTextInputHandler* handler, gint keyval, gint state = 0) { @@ -189,420 +152,391 @@ static void send_key_event(FlTextInputHandler* handler, } TEST(FlTextInputHandlerTest, MessageHandler) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - EXPECT_TRUE(messenger.HasMessageHandler("flutter/textinput")); + EXPECT_TRUE( + fl_mock_binary_messenger_has_handler(messenger, "flutter/textinput")); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, SetClient) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - g_autoptr(FlValue) args = build_input_config({.client_id = 1}); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); + set_client(messenger, {.client_id = 1}); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", message); + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, Show) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); EXPECT_CALL(context, gtk_im_context_focus_in(::testing::Eq(context))); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.show", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.show", nullptr, nullptr); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); - messenger.ReceiveMessage("flutter/textinput", message); + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, Hide) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); EXPECT_CALL(context, gtk_im_context_focus_out(::testing::Eq(context))); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.hide", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.hide", nullptr, nullptr); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - messenger.ReceiveMessage("flutter/textinput", message); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, ClearClient) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.clearClient", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.clearClient", nullptr, nullptr); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); - messenger.ReceiveMessage("flutter/textinput", message); + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, PerformAction) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set input config - g_autoptr(FlValue) config = build_input_config({ - .client_id = 1, - .input_type = "TextInputType.multiline", - .input_action = "TextInputAction.newline", - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 7, - .selection_extent = 7, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); - - // update editing state - g_autoptr(FlValue) new_state = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter\n", - .selection_base = 8, - .selection_extent = 8, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(new_state)), - ::testing::_, ::testing::_, ::testing::_)); - - // perform action - g_autoptr(FlValue) action = build_list({ - fl_value_new_int(1), // client_id - fl_value_new_string("TextInputAction.newline"), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.performAction", - FlValueEq(action)), - ::testing::_, ::testing::_, ::testing::_)); + set_client(messenger, { + .client_id = 1, + .input_type = "TextInputType.multiline", + .input_action = "TextInputAction.newline", + }); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 7, + .selection_extent = 7, + }); + + // Client will update editing state and perform action + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + if (strcmp(name, "TextInputClient.updateEditingState") == 0) { + g_autoptr(FlValue) expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter\n", + .selection_base = 8, + .selection_extent = 8, + }), + }); + EXPECT_TRUE(fl_value_equal(args, expected_args)); + EXPECT_EQ(*call_count, 0); + (*call_count)++; + } else if (strcmp(name, "TextInputClient.performAction") == 0) { + g_autoptr(FlValue) expected_args = build_list({ + fl_value_new_int(1), // client_id + fl_value_new_string("TextInputAction.newline"), + }); + EXPECT_TRUE(fl_value_equal(args, expected_args)); + EXPECT_EQ(*call_count, 1); + (*call_count)++; + } + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_Return); + EXPECT_EQ(call_count, 2); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } // Regression test for https://github.com/flutter/flutter/issues/125879. TEST(FlTextInputHandlerTest, MultilineWithSendAction) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // Set input config. - g_autoptr(FlValue) config = build_input_config({ - .client_id = 1, - .input_type = "TextInputType.multiline", - .input_action = "TextInputAction.send", - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // Set editing state. - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 7, - .selection_extent = 7, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); - - // Perform action. - g_autoptr(FlValue) action = build_list({ - fl_value_new_int(1), // client_id - fl_value_new_string("TextInputAction.send"), - }); + set_client(messenger, { + .client_id = 1, + .input_type = "TextInputType.multiline", + .input_action = "TextInputAction.send", + }); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 7, + .selection_extent = 7, + }); // Because the input action is not set to TextInputAction.newline, the next // expected call is "TextInputClient.performAction". If the input action was // set to TextInputAction.newline the next call would be // "TextInputClient.updateEditingState" (this case is tested in the test named // 'PerformAction'). - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.performAction", - FlValueEq(action)), - ::testing::_, ::testing::_, ::testing::_)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.performAction"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // Perform action. + expected_args = build_list({ + fl_value_new_int(1), // client_id + fl_value_new_string("TextInputAction.send"), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_Return); + EXPECT_EQ(call_count, 1); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, MoveCursor) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set input config - g_autoptr(FlValue) config = build_input_config({.client_id = 1}); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 4, - .selection_extent = 4, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); - - // move cursor to beginning - g_autoptr(FlValue) beginning = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 0, - .selection_extent = 0, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(beginning)), - ::testing::_, ::testing::_, ::testing::_)); + set_client(messenger, {.client_id = 1}); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 4, + .selection_extent = 4, + }); + + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.updateEditingState"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // move cursor to beginning + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 0, + .selection_extent = 0, + }), + }); + break; + case 1: + // move cursor to end + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 7, + .selection_extent = 7, + }), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_Home); - - // move cursor to end - g_autoptr(FlValue) end = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 7, - .selection_extent = 7, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(end)), - ::testing::_, ::testing::_, ::testing::_)); - send_key_event(handler, GDK_KEY_End); + EXPECT_EQ(call_count, 2); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, Select) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set input config - g_autoptr(FlValue) config = build_input_config({.client_id = 1}); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 4, - .selection_extent = 4, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); - - // select to end - g_autoptr(FlValue) select_to_end = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 4, - .selection_extent = 7, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(select_to_end)), - ::testing::_, ::testing::_, ::testing::_)); + set_client(messenger, {.client_id = 1}); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 4, + .selection_extent = 4, + }); + + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.updateEditingState"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // select to end + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 4, + .selection_extent = 7, + }), + }); + break; + case 1: + // select to beginning + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 4, + .selection_extent = 0, + }), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_End, GDK_SHIFT_MASK); - - // select to beginning - g_autoptr(FlValue) select_to_beginning = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 4, - .selection_extent = 0, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(select_to_beginning)), - ::testing::_, ::testing::_, ::testing::_)); - send_key_event(handler, GDK_KEY_Home, GDK_SHIFT_MASK); + EXPECT_EQ(call_count, 2); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, Composing) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - g_signal_emit_by_name(context, "preedit-start", nullptr); - // update EXPECT_CALL(context, gtk_im_context_get_preedit_string( @@ -612,94 +546,85 @@ TEST(FlTextInputHandlerTest, Composing) { ::testing::DoAll(::testing::SetArgPointee<1>(g_strdup("Flutter")), ::testing::SetArgPointee<3>(0))); - g_autoptr(FlValue) state = build_list({ - fl_value_new_int(-1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 0, - .selection_extent = 0, - .composing_base = 0, - .composing_extent = 7, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(state)), - ::testing::_, ::testing::_, ::testing::_)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.updateEditingState"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + expected_args = build_list({ + fl_value_new_int(-1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 0, + .selection_extent = 0, + .composing_base = 0, + .composing_extent = 7, + }), + }); + break; + case 1: + // commit + expected_args = build_list({ + fl_value_new_int(-1), // client_id + build_editing_state({ + .text = "engine", + .selection_base = 6, + .selection_extent = 6, + }), + }); + break; + case 2: + // end + expected_args = build_list({ + fl_value_new_int(-1), // client_id + build_editing_state({ + .text = "engine", + .selection_base = 6, + .selection_extent = 6, + }), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); + g_signal_emit_by_name(context, "preedit-start", nullptr); g_signal_emit_by_name(context, "preedit-changed", nullptr); - - // commit - g_autoptr(FlValue) commit = build_list({ - fl_value_new_int(-1), // client_id - build_editing_state({ - .text = "engine", - .selection_base = 6, - .selection_extent = 6, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(commit)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "engine", nullptr); - - // end - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - ::testing::_), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "preedit-end", nullptr); + EXPECT_EQ(call_count, 3); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, SurroundingText) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set input config - g_autoptr(FlValue) config = build_input_config({.client_id = 1}); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 3, - .selection_extent = 3, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); + set_client(messenger, {.client_id = 1}); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 3, + .selection_extent = 3, + }); // retrieve EXPECT_CALL(context, gtk_im_context_set_surrounding( @@ -710,35 +635,53 @@ TEST(FlTextInputHandlerTest, SurroundingText) { g_signal_emit_by_name(context, "retrieve-surrounding", &retrieved, nullptr); EXPECT_TRUE(retrieved); - // delete - g_autoptr(FlValue) update = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutr", - .selection_base = 3, - .selection_extent = 3, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(update)), - ::testing::_, ::testing::_, ::testing::_)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.updateEditingState"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // delete + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutr", + .selection_base = 3, + .selection_extent = 3, + }), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); gboolean deleted = false; g_signal_emit_by_name(context, "delete-surrounding", 1, 2, &deleted, nullptr); EXPECT_TRUE(deleted); + EXPECT_EQ(call_count, 1); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, SetMarkedTextRect) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); g_signal_emit_by_name(context, "preedit-start", nullptr); @@ -767,35 +710,24 @@ TEST(FlTextInputHandlerTest, SetMarkedTextRect) { }), }, }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_editable_size_and_transform = - fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditableSizeAndTransform", - size_and_transform, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", - set_editable_size_and_transform); - - // set marked text rect - g_autoptr(FlValue) rect = build_map({ - {"x", fl_value_new_float(1)}, - {"y", fl_value_new_float(2)}, - {"width", fl_value_new_float(3)}, - {"height", fl_value_new_float(4)}, - }); - g_autoptr(GBytes) set_marked_text_rect = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setMarkedTextRect", rect, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.setEditableSizeAndTransform", + size_and_transform, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); EXPECT_CALL(delegate, fl_text_input_view_delegate_translate_coordinates( ::testing::Eq(delegate), @@ -812,34 +744,47 @@ TEST(FlTextInputHandlerTest, SetMarkedTextRect) { ::testing::Field(&GdkRectangle::width, 0), ::testing::Field(&GdkRectangle::height, 0))))); - messenger.ReceiveMessage("flutter/textinput", set_marked_text_rect); + // set marked text rect + g_autoptr(FlValue) rect = build_map({ + {"x", fl_value_new_float(1)}, + {"y", fl_value_new_float(2)}, + {"width", fl_value_new_float(3)}, + {"height", fl_value_new_float(4)}, + }); + called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.setMarkedTextRect", rect, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, TextInputTypeNone) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - g_autoptr(FlValue) args = build_input_config({ - .client_id = 1, - .input_type = "TextInputType.none", - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::A(), - SuccessResponse(null), ::testing::A())) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); + set_client(messenger, { + .client_id = 1, + .input_type = "TextInputType.none", + }); EXPECT_CALL(context, gtk_im_context_focus_in(::testing::Eq(context))) @@ -847,115 +792,106 @@ TEST(FlTextInputHandlerTest, TextInputTypeNone) { EXPECT_CALL(context, gtk_im_context_focus_out(::testing::Eq(context))); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.show", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - g_autoptr(GBytes) show = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.show", nullptr, nullptr); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); - messenger.ReceiveMessage("flutter/textinput", show); + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, TextEditingDelta) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set config - g_autoptr(FlValue) args = build_input_config({ - .client_id = 1, - .enable_delta_model = true, - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::A(), - SuccessResponse(null), ::testing::A())) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 7, - .selection_extent = 7, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); + set_client(messenger, { + .client_id = 1, + .enable_delta_model = true, + }); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 7, + .selection_extent = 7, + }); // update editing state with deltas - g_autoptr(FlValue) deltas = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutter", - .delta_text = "Flutter", - .delta_start = 7, - .delta_end = 7, - .selection_base = 0, - .selection_extent = 0, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(deltas)), - ::testing::_, ::testing::_, ::testing::_)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutter", + .delta_text = "Flutter", + .delta_start = 7, + .delta_end = 7, + .selection_base = 0, + .selection_extent = 0, + }), + }), + }}), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_Home); + EXPECT_EQ(call_count, 1); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, ComposingDelta) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); // set config - g_autoptr(FlValue) args = build_input_config({ - .client_id = 1, - .enable_delta_model = true, - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::A(), - SuccessResponse(null), ::testing::A())) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); + set_client(messenger, { + .client_id = 1, + .enable_delta_model = true, + }); g_signal_emit_by_name(context, "preedit-start", nullptr); @@ -968,325 +904,283 @@ TEST(FlTextInputHandlerTest, ComposingDelta) { ::testing::DoAll(::testing::SetArgPointee<1>(g_strdup("Flutter ")), ::testing::SetArgPointee<3>(8))); - g_autoptr(FlValue) update = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "", - .delta_text = "Flutter ", - .delta_start = 0, - .delta_end = 0, - .selection_base = 8, - .selection_extent = 8, - .composing_base = 0, - .composing_extent = 8, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(update)), - ::testing::_, ::testing::_, ::testing::_)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "", + .delta_text = "Flutter ", + .delta_start = 0, + .delta_end = 0, + .selection_base = 8, + .selection_extent = 8, + .composing_base = 0, + .composing_extent = 8, + }), + }), + }}), + }); + break; + case 1: + // commit + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutter ", + .delta_text = "Flutter engine", + .delta_start = 0, + .delta_end = 8, + .selection_base = 14, + .selection_extent = 14, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 2: + // end + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutter engine", + .selection_base = 14, + .selection_extent = 14, + }), + }), + }}), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); g_signal_emit_by_name(context, "preedit-changed", nullptr); - - // commit - g_autoptr(FlValue) commit = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutter ", - .delta_text = "Flutter engine", - .delta_start = 0, - .delta_end = 8, - .selection_base = 14, - .selection_extent = 14, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commit)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "Flutter engine", nullptr); - - // end - g_autoptr(FlValue) end = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutter engine", - .selection_base = 14, - .selection_extent = 14, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(end)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "preedit-end", nullptr); + EXPECT_EQ(call_count, 3); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, NonComposingDelta) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); // set config - g_autoptr(FlValue) args = build_input_config({ - .client_id = 1, - .enable_delta_model = true, - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::A(), - SuccessResponse(null), ::testing::A())) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // commit F - g_autoptr(FlValue) commit = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "", - .delta_text = "F", - .delta_start = 0, - .delta_end = 0, - .selection_base = 1, - .selection_extent = 1, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commit)), - ::testing::_, ::testing::_, ::testing::_)); + set_client(messenger, { + .client_id = 1, + .enable_delta_model = true, + }); + + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // commit F + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "", + .delta_text = "F", + .delta_start = 0, + .delta_end = 0, + .selection_base = 1, + .selection_extent = 1, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 1: + // commit l + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "F", + .delta_text = "l", + .delta_start = 1, + .delta_end = 1, + .selection_base = 2, + .selection_extent = 2, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 2: + // commit u + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Fl", + .delta_text = "u", + .delta_start = 2, + .delta_end = 2, + .selection_base = 3, + .selection_extent = 3, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 3: + // commit t + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flu", + .delta_text = "t", + .delta_start = 3, + .delta_end = 3, + .selection_base = 4, + .selection_extent = 4, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 4: + // commit t again + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flut", + .delta_text = "t", + .delta_start = 4, + .delta_end = 4, + .selection_base = 5, + .selection_extent = 5, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 5: + // commit e + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutt", + .delta_text = "e", + .delta_start = 5, + .delta_end = 5, + .selection_base = 6, + .selection_extent = 6, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 6: + // commit r + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutte", + .delta_text = "r", + .delta_start = 6, + .delta_end = 6, + .selection_base = 7, + .selection_extent = 7, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); g_signal_emit_by_name(context, "commit", "F", nullptr); - - // commit l - g_autoptr(FlValue) commitL = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "F", - .delta_text = "l", - .delta_start = 1, - .delta_end = 1, - .selection_base = 2, - .selection_extent = 2, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitL)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "l", nullptr); - - // commit u - g_autoptr(FlValue) commitU = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Fl", - .delta_text = "u", - .delta_start = 2, - .delta_end = 2, - .selection_base = 3, - .selection_extent = 3, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitU)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "u", nullptr); - - // commit t - g_autoptr(FlValue) commitTa = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flu", - .delta_text = "t", - .delta_start = 3, - .delta_end = 3, - .selection_base = 4, - .selection_extent = 4, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitTa)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "t", nullptr); - - // commit t again - g_autoptr(FlValue) commitTb = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flut", - .delta_text = "t", - .delta_start = 4, - .delta_end = 4, - .selection_base = 5, - .selection_extent = 5, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitTb)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "t", nullptr); - - // commit e - g_autoptr(FlValue) commitE = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutt", - .delta_text = "e", - .delta_start = 5, - .delta_end = 5, - .selection_base = 6, - .selection_extent = 6, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitE)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "e", nullptr); - - // commit r - g_autoptr(FlValue) commitR = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutte", - .delta_text = "r", - .delta_start = 6, - .delta_end = 6, - .selection_base = 7, - .selection_extent = 7, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitR)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "r", nullptr); + EXPECT_EQ(call_count, 7); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } diff --git a/shell/platform/linux/fl_window_state_monitor_test.cc b/shell/platform/linux/fl_window_state_monitor_test.cc index f88450741e10c..8aa6588d44ddb 100644 --- a/shell/platform/linux/fl_window_state_monitor_test.cc +++ b/shell/platform/linux/fl_window_state_monitor_test.cc @@ -3,254 +3,287 @@ // found in the LICENSE file. #include "flutter/shell/platform/linux/fl_window_state_monitor.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_string_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/fl_mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/mock_window.h" #include "gtest/gtest.h" -// Matches if a FlValue is a the supplied string. -class FlValueStringMatcher { - public: - using is_gtest_matcher = void; - - explicit FlValueStringMatcher(::testing::Matcher value) - : value_(std::move(value)) {} - - bool MatchAndExplain(GBytes* data, - ::testing::MatchResultListener* result_listener) const { - g_autoptr(FlStringCodec) codec = fl_string_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(FlValue) value = - fl_message_codec_decode_message(FL_MESSAGE_CODEC(codec), data, &error); - if (value == nullptr) { - *result_listener << ::testing::PrintToString(error->message); - return false; - } - if (!value_.MatchAndExplain(fl_value_get_string(value), result_listener)) { - *result_listener << " where the value doesn't match: \"" << value << "\""; - return false; - } - return true; - } - - void DescribeTo(std::ostream* os) const { - *os << "value "; - value_.DescribeTo(os); - } - - void DescribeNegationTo(std::ostream* os) const { - *os << "value "; - value_.DescribeNegationTo(os); - } - - private: - ::testing::Matcher value_; -}; - -::testing::Matcher LifecycleString(const std::string& value) { - return FlValueStringMatcher(::testing::StrEq(value)); -} - TEST(FlWindowStateMonitorTest, GainFocus) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(static_cast(0))); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.resumed"), - ::testing::_, ::testing::_, ::testing::_)); + + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.resumed"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = GDK_WINDOW_STATE_FOCUSED}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LoseFocus) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_FOCUSED)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.inactive"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), + "AppLifecycleState.inactive"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast(0)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, EnterIconified) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(static_cast(0))); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.hidden"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.hidden"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = GDK_WINDOW_STATE_ICONIFIED}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LeaveIconified) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_ICONIFIED)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.inactive"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), + "AppLifecycleState.inactive"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast(0)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LeaveIconifiedFocused) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_ICONIFIED)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.resumed"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.resumed"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast( GDK_WINDOW_STATE_FOCUSED)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, EnterWithdrawn) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(static_cast(0))); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.hidden"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.hidden"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = GDK_WINDOW_STATE_WITHDRAWN}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LeaveWithdrawn) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_WITHDRAWN)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.inactive"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), + "AppLifecycleState.inactive"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast(0)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LeaveWithdrawnFocused) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_WITHDRAWN)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.resumed"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.resumed"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast( GDK_WINDOW_STATE_FOCUSED)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } diff --git a/shell/platform/linux/testing/fl_mock_binary_messenger.cc b/shell/platform/linux/testing/fl_mock_binary_messenger.cc new file mode 100644 index 0000000000000..e26f9bcfcbb49 --- /dev/null +++ b/shell/platform/linux/testing/fl_mock_binary_messenger.cc @@ -0,0 +1,609 @@ +// 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/testing/fl_mock_binary_messenger.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/public/flutter_linux/fl_json_message_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h" + +G_DECLARE_FINAL_TYPE(FlMockBinaryMessengerResponseHandle, + fl_mock_binary_messenger_response_handle, + FL, + MOCK_BINARY_MESSENGER_RESPONSE_HANDLE, + FlBinaryMessengerResponseHandle) + +struct _FlMockBinaryMessengerResponseHandle { + FlBinaryMessengerResponseHandle parent_instance; + + FlMockBinaryMessengerCallback callback; + gpointer user_data; +}; + +G_DEFINE_TYPE(FlMockBinaryMessengerResponseHandle, + fl_mock_binary_messenger_response_handle, + fl_binary_messenger_response_handle_get_type()) + +static void fl_mock_binary_messenger_response_handle_class_init( + FlMockBinaryMessengerResponseHandleClass* klass) {} + +static void fl_mock_binary_messenger_response_handle_init( + FlMockBinaryMessengerResponseHandle* self) {} + +FlMockBinaryMessengerResponseHandle* +fl_mock_binary_messenger_response_handle_new( + FlMockBinaryMessengerCallback callback, + gpointer user_data) { + FlMockBinaryMessengerResponseHandle* self = + FL_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE(g_object_new( + fl_mock_binary_messenger_response_handle_get_type(), nullptr)); + self->callback = callback; + self->user_data = user_data; + return self; +} + +struct _FlMockBinaryMessenger { + GObject parent_instance; + + // Handlers the embedder has registered. + GHashTable* handlers; + + // Mocked Dart channels. + GHashTable* mock_channels; + GHashTable* mock_message_channels; + GHashTable* mock_method_channels; +}; + +typedef struct { + FlMockBinaryMessengerChannelHandler callback; + gpointer user_data; +} MockChannel; + +static MockChannel* mock_channel_new( + FlMockBinaryMessengerChannelHandler callback, + gpointer user_data) { + MockChannel* channel = g_new0(MockChannel, 1); + channel->callback = callback; + channel->user_data = user_data; + return channel; +} + +static void mock_channel_free(MockChannel* channel) { + g_free(channel); +} + +typedef struct { + FlMessageCodec* codec; + FlMockBinaryMessengerMessageChannelHandler callback; + gpointer user_data; +} MockMessageChannel; + +static MockMessageChannel* mock_message_channel_new( + FlMockBinaryMessengerMessageChannelHandler callback, + FlMessageCodec* codec, + gpointer user_data) { + MockMessageChannel* channel = g_new0(MockMessageChannel, 1); + channel->codec = FL_MESSAGE_CODEC(g_object_ref(codec)); + channel->callback = callback; + channel->user_data = user_data; + return channel; +} + +static void mock_message_channel_free(MockMessageChannel* channel) { + g_object_unref(channel->codec); + g_free(channel); +} + +typedef struct { + FlMethodCodec* codec; + FlMockBinaryMessengerMethodChannelHandler callback; + gpointer user_data; +} MockMethodChannel; + +static MockMethodChannel* mock_method_channel_new( + FlMockBinaryMessengerMethodChannelHandler callback, + FlMethodCodec* codec, + gpointer user_data) { + MockMethodChannel* channel = g_new0(MockMethodChannel, 1); + channel->codec = FL_METHOD_CODEC(g_object_ref(codec)); + channel->callback = callback; + channel->user_data = user_data; + return channel; +} + +static void mock_method_channel_free(MockMethodChannel* channel) { + g_object_unref(channel->codec); + g_free(channel); +} + +typedef struct { + FlBinaryMessengerMessageHandler callback; + gpointer user_data; + GDestroyNotify destroy_notify; +} Handler; + +static Handler* handler_new(FlBinaryMessengerMessageHandler callback, + gpointer user_data, + GDestroyNotify destroy_notify) { + Handler* handler = g_new0(Handler, 1); + handler->callback = callback; + handler->user_data = user_data; + handler->destroy_notify = destroy_notify; + return handler; +} + +static void handler_free(Handler* handler) { + if (handler->destroy_notify) { + handler->destroy_notify(handler->user_data); + } + g_free(handler); +} + +static void fl_mock_binary_messenger_iface_init( + FlBinaryMessengerInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlMockBinaryMessenger, + fl_mock_binary_messenger, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_binary_messenger_get_type(), + fl_mock_binary_messenger_iface_init)) + +static void fl_mock_binary_messenger_set_message_handler_on_channel( + FlBinaryMessenger* messenger, + const gchar* channel, + FlBinaryMessengerMessageHandler handler, + gpointer user_data, + GDestroyNotify destroy_notify) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); + g_hash_table_insert(self->handlers, g_strdup(channel), + handler_new(handler, user_data, destroy_notify)); +} + +static gboolean fl_mock_binary_messenger_send_response( + FlBinaryMessenger* messenger, + FlBinaryMessengerResponseHandle* response_handle, + GBytes* response, + GError** error) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); + + g_return_val_if_fail( + FL_IS_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle), FALSE); + FlMockBinaryMessengerResponseHandle* handle = + FL_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle); + + handle->callback(self, response, handle->user_data); + + return TRUE; +} + +static void fl_mock_binary_messenger_send_on_channel( + FlBinaryMessenger* messenger, + const gchar* channel, + GBytes* message, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); + g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data); + + MockChannel* mock_channel = static_cast( + g_hash_table_lookup(self->mock_channels, channel)); + MockMessageChannel* mock_message_channel = static_cast( + g_hash_table_lookup(self->mock_message_channels, channel)); + MockMethodChannel* mock_method_channel = static_cast( + g_hash_table_lookup(self->mock_method_channels, channel)); + g_autoptr(GBytes) response = nullptr; + if (mock_channel != nullptr) { + response = mock_channel->callback(self, message, mock_channel->user_data); + } else if (mock_message_channel != nullptr) { + g_autoptr(GError) error = nullptr; + g_autoptr(FlValue) message_value = fl_message_codec_decode_message( + mock_message_channel->codec, message, &error); + if (message_value == nullptr) { + g_warning("Failed to decode message: %s", error->message); + } else { + g_autoptr(FlValue) response_value = mock_message_channel->callback( + self, message_value, mock_message_channel->user_data); + response = fl_message_codec_encode_message(mock_message_channel->codec, + response_value, &error); + if (response == nullptr) { + g_warning("Failed to encode message: %s", error->message); + } + } + } else if (mock_method_channel != nullptr) { + g_autofree gchar* name = nullptr; + g_autoptr(FlValue) args = nullptr; + g_autoptr(GError) error = nullptr; + if (!fl_method_codec_decode_method_call(mock_method_channel->codec, message, + &name, &args, &error)) { + g_warning("Failed to decode method call: %s", error->message); + } else { + g_autoptr(FlMethodResponse) response_value = + mock_method_channel->callback(self, name, args, + mock_method_channel->user_data); + response = fl_method_codec_encode_response(mock_method_channel->codec, + response_value, &error); + if (response == nullptr) { + g_warning("Failed to encode method response: %s", error->message); + } + } + } + + if (response == nullptr) { + response = g_bytes_new(nullptr, 0); + } + + g_task_return_pointer(task, g_bytes_ref(response), + reinterpret_cast(g_bytes_unref)); +} + +static GBytes* fl_mock_binary_messenger_send_on_channel_finish( + FlBinaryMessenger* messenger, + GAsyncResult* result, + GError** error) { + return static_cast(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) {} + +static void fl_mock_binary_messenger_set_warns_on_channel_overflow( + FlBinaryMessenger* messenger, + const gchar* channel, + bool warns) {} + +static void fl_mock_binary_messenger_shutdown(FlBinaryMessenger* messenger) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); + g_hash_table_remove_all(self->handlers); +} + +static void fl_mock_binary_messenger_dispose(GObject* object) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(object); + + g_clear_pointer(&self->mock_channels, g_hash_table_unref); + g_clear_pointer(&self->mock_message_channels, g_hash_table_unref); + g_clear_pointer(&self->mock_method_channels, g_hash_table_unref); + + G_OBJECT_CLASS(fl_mock_binary_messenger_parent_class)->dispose(object); +} + +static void fl_mock_binary_messenger_class_init( + FlMockBinaryMessengerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_mock_binary_messenger_dispose; +} + +static void fl_mock_binary_messenger_iface_init( + FlBinaryMessengerInterface* iface) { + iface->set_message_handler_on_channel = + fl_mock_binary_messenger_set_message_handler_on_channel; + iface->send_response = fl_mock_binary_messenger_send_response; + iface->send_on_channel = fl_mock_binary_messenger_send_on_channel; + iface->send_on_channel_finish = + fl_mock_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; + iface->shutdown = fl_mock_binary_messenger_shutdown; +} + +static void fl_mock_binary_messenger_init(FlMockBinaryMessenger* self) { + self->handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)handler_free); + + self->mock_channels = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, (GDestroyNotify)mock_channel_free); + self->mock_message_channels = + g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)mock_message_channel_free); + self->mock_method_channels = + g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)mock_method_channel_free); +} + +FlMockBinaryMessenger* fl_mock_binary_messenger_new() { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER( + g_object_new(fl_mock_binary_messenger_get_type(), nullptr)); + return self; +} + +gboolean fl_mock_binary_messenger_has_handler(FlMockBinaryMessenger* self, + const gchar* channel) { + g_return_val_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self), FALSE); + return g_hash_table_lookup(self->handlers, channel) != nullptr; +} + +void fl_mock_binary_messenger_set_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_hash_table_insert(self->mock_channels, g_strdup(channel), + mock_channel_new(handler, user_data)); +} + +void fl_mock_binary_messenger_set_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMessageCodec* codec, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_hash_table_insert(self->mock_message_channels, g_strdup(channel), + mock_message_channel_new(handler, codec, user_data)); +} + +void fl_mock_binary_messenger_set_standard_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new(); + return fl_mock_binary_messenger_set_message_channel( + self, channel, FL_MESSAGE_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_set_string_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(FlStringCodec) codec = fl_string_codec_new(); + return fl_mock_binary_messenger_set_message_channel( + self, channel, FL_MESSAGE_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_set_json_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + return fl_mock_binary_messenger_set_message_channel( + self, channel, FL_MESSAGE_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_set_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_hash_table_insert(self->mock_method_channels, g_strdup(channel), + mock_method_channel_new(handler, codec, user_data)); +} + +void fl_mock_binary_messenger_set_standard_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + fl_mock_binary_messenger_set_method_channel( + self, channel, FL_METHOD_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_set_json_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + fl_mock_binary_messenger_set_method_channel( + self, channel, FL_METHOD_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_send(FlMockBinaryMessenger* self, + const gchar* channel, + GBytes* message, + FlMockBinaryMessengerCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + Handler* handler = + static_cast(g_hash_table_lookup(self->handlers, channel)); + if (handler == nullptr) { + return; + } + + handler->callback( + FL_BINARY_MESSENGER(self), channel, message, + FL_BINARY_MESSENGER_RESPONSE_HANDLE( + fl_mock_binary_messenger_response_handle_new(callback, user_data)), + handler->user_data); +} + +typedef struct { + FlMessageCodec* codec; + FlMockBinaryMessengerMessageCallback callback; + gpointer user_data; +} SendMessageData; + +static SendMessageData* send_message_data_new( + FlMessageCodec* codec, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data) { + SendMessageData* data = g_new0(SendMessageData, 1); + data->codec = FL_MESSAGE_CODEC(g_object_ref(codec)); + data->callback = callback; + data->user_data = user_data; + return data; +} + +static void send_message_data_free(SendMessageData* data) { + g_object_unref(data->codec); + free(data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(SendMessageData, send_message_data_free) + +static void send_message_cb(FlMockBinaryMessenger* self, + GBytes* response, + gpointer user_data) { + g_autoptr(SendMessageData) data = static_cast(user_data); + + g_autoptr(GError) error = nullptr; + g_autoptr(FlValue) response_value = + fl_message_codec_decode_message(data->codec, response, &error); + if (response_value == nullptr) { + g_warning("Failed to decode message response: %s", error->message); + return; + } + + data->callback(self, response_value, data->user_data); +} + +void fl_mock_binary_messenger_send_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMessageCodec* codec, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) encoded_message = + fl_message_codec_encode_message(codec, message, &error); + if (encoded_message == nullptr) { + g_warning("Failed to encode message: %s", error->message); + return; + } + + fl_mock_binary_messenger_send( + self, channel, encoded_message, send_message_cb, + send_message_data_new(codec, callback, user_data)); +} + +void fl_mock_binary_messenger_send_standard_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new(); + fl_mock_binary_messenger_send_message(self, channel, FL_MESSAGE_CODEC(codec), + message, callback, user_data); +} + +void fl_mock_binary_messenger_send_json_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + fl_mock_binary_messenger_send_message(self, channel, FL_MESSAGE_CODEC(codec), + message, callback, user_data); +} + +typedef struct { + FlMethodCodec* codec; + FlMockBinaryMessengerMethodCallback callback; + gpointer user_data; +} InvokeMethodData; + +static InvokeMethodData* invoke_method_data_new( + FlMethodCodec* codec, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data) { + InvokeMethodData* data = g_new0(InvokeMethodData, 1); + data->codec = FL_METHOD_CODEC(g_object_ref(codec)); + data->callback = callback; + data->user_data = user_data; + return data; +} + +static void invoke_method_data_free(InvokeMethodData* data) { + g_object_unref(data->codec); + free(data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(InvokeMethodData, invoke_method_data_free) + +static void invoke_method_cb(FlMockBinaryMessenger* self, + GBytes* response, + gpointer user_data) { + g_autoptr(InvokeMethodData) data = static_cast(user_data); + + g_autoptr(GError) error = nullptr; + g_autoptr(FlMethodResponse) method_response = + fl_method_codec_decode_response(data->codec, response, &error); + if (method_response == nullptr) { + g_warning("Failed to decode method response: %s", error->message); + return; + } + + data->callback(self, method_response, data->user_data); +} + +void fl_mock_binary_messenger_invoke_method( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) message = + fl_method_codec_encode_method_call(codec, name, args, &error); + if (message == nullptr) { + g_warning("Failed to encode method call: %s", error->message); + return; + } + + fl_mock_binary_messenger_send( + self, channel, message, invoke_method_cb, + invoke_method_data_new(codec, callback, user_data)); +} + +void fl_mock_binary_messenger_invoke_standard_method( + FlMockBinaryMessenger* self, + const gchar* channel, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + fl_mock_binary_messenger_invoke_method(self, channel, FL_METHOD_CODEC(codec), + name, args, callback, user_data); +} + +void fl_mock_binary_messenger_invoke_json_method( + FlMockBinaryMessenger* self, + const gchar* channel, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + fl_mock_binary_messenger_invoke_method(self, channel, FL_METHOD_CODEC(codec), + name, args, callback, user_data); +} diff --git a/shell/platform/linux/testing/fl_mock_binary_messenger.h b/shell/platform/linux/testing/fl_mock_binary_messenger.h new file mode 100644 index 0000000000000..ab6276e2917e3 --- /dev/null +++ b/shell/platform/linux/testing/fl_mock_binary_messenger.h @@ -0,0 +1,160 @@ +// 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_TESTING_FL_MOCK_BINARY_MESSENGER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_FL_MOCK_BINARY_MESSENGER_H_ + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlMockBinaryMessenger, + fl_mock_binary_messenger, + FL, + MOCK_BINARY_MESSENGER, + GObject) + +typedef GBytes* (*FlMockBinaryMessengerChannelHandler)( + FlMockBinaryMessenger* messenger, + GBytes* message, + gpointer user_data); + +typedef FlValue* (*FlMockBinaryMessengerMessageChannelHandler)( + FlMockBinaryMessenger* messenger, + FlValue* message, + gpointer user_data); + +typedef FlMethodResponse* (*FlMockBinaryMessengerMethodChannelHandler)( + FlMockBinaryMessenger* messenger, + const gchar* name, + FlValue* args, + gpointer user_data); + +typedef void (*FlMockBinaryMessengerCallback)(FlMockBinaryMessenger* messenger, + GBytes* response, + gpointer user_data); + +typedef void (*FlMockBinaryMessengerMessageCallback)( + FlMockBinaryMessenger* messenger, + FlValue* response, + gpointer user_data); + +typedef void (*FlMockBinaryMessengerMethodCallback)( + FlMockBinaryMessenger* messenger, + FlMethodResponse* response, + gpointer user_data); + +FlMockBinaryMessenger* fl_mock_binary_messenger_new(); + +gboolean fl_mock_binary_messenger_has_handler(FlMockBinaryMessenger* self, + const gchar* channel); + +void fl_mock_binary_messenger_set_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMessageCodec* codec, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_standard_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_string_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_json_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_standard_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_json_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_send(FlMockBinaryMessenger* self, + const gchar* channel, + GBytes* message, + FlMockBinaryMessengerCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_send_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMessageCodec* codec, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_send_standard_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_send_json_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_invoke_method( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_invoke_standard_method( + FlMockBinaryMessenger* self, + const gchar* channel, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_invoke_json_method( + FlMockBinaryMessenger* self, + const gchar* channel, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_FL_MOCK_BINARY_MESSENGER_H_ diff --git a/shell/platform/linux/testing/mock_binary_messenger.cc b/shell/platform/linux/testing/mock_binary_messenger.cc deleted file mode 100644 index 8b22f2291bd75..0000000000000 --- a/shell/platform/linux/testing/mock_binary_messenger.cc +++ /dev/null @@ -1,160 +0,0 @@ -// 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/testing/mock_binary_messenger.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h" - -using namespace flutter::testing; - -G_DECLARE_FINAL_TYPE(FlMockBinaryMessenger, - fl_mock_binary_messenger, - FL, - MOCK_BINARY_MESSENGER, - GObject) - -struct _FlMockBinaryMessenger { - GObject parent_instance; - MockBinaryMessenger* mock; -}; - -static FlBinaryMessenger* fl_mock_binary_messenger_new( - MockBinaryMessenger* mock) { - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER( - g_object_new(fl_mock_binary_messenger_get_type(), nullptr)); - self->mock = mock; - return FL_BINARY_MESSENGER(self); -} - -MockBinaryMessenger::MockBinaryMessenger() - : instance_(fl_mock_binary_messenger_new(this)) {} - -MockBinaryMessenger::~MockBinaryMessenger() { - if (FL_IS_BINARY_MESSENGER(instance_)) { - g_clear_object(&instance_); - } -} - -MockBinaryMessenger::operator FlBinaryMessenger*() { - return instance_; -} - -bool MockBinaryMessenger::HasMessageHandler(const gchar* channel) const { - return message_handlers_.at(channel) != nullptr; -} - -void MockBinaryMessenger::SetMessageHandler( - const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data) { - message_handlers_[channel] = handler; - user_datas_[channel] = user_data; -} - -void MockBinaryMessenger::ReceiveMessage(const gchar* channel, - GBytes* message) { - FlBinaryMessengerMessageHandler handler = message_handlers_[channel]; - if (response_handles_[channel] == nullptr) { - response_handles_[channel] = FL_BINARY_MESSENGER_RESPONSE_HANDLE( - fl_mock_binary_messenger_response_handle_new()); - } - handler(instance_, channel, message, response_handles_[channel], - user_datas_[channel]); -} - -static void fl_mock_binary_messenger_iface_init( - FlBinaryMessengerInterface* iface); - -G_DEFINE_TYPE_WITH_CODE( - FlMockBinaryMessenger, - fl_mock_binary_messenger, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(fl_binary_messenger_get_type(), - fl_mock_binary_messenger_iface_init)) - -static void fl_mock_binary_messenger_class_init( - FlMockBinaryMessengerClass* klass) {} - -static void fl_mock_binary_messenger_set_message_handler_on_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data, - GDestroyNotify destroy_notify) { - g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger)); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - self->mock->SetMessageHandler(channel, handler, user_data); - self->mock->fl_binary_messenger_set_message_handler_on_channel( - messenger, channel, handler, user_data, destroy_notify); -} - -static gboolean fl_mock_binary_messenger_send_response( - FlBinaryMessenger* messenger, - FlBinaryMessengerResponseHandle* response_handle, - GBytes* response, - GError** error) { - g_return_val_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger), false); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - return self->mock->fl_binary_messenger_send_response( - messenger, response_handle, response, error); -} - -static void fl_mock_binary_messenger_send_on_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data) { - g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger)); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - self->mock->fl_binary_messenger_send_on_channel( - messenger, channel, message, cancellable, callback, user_data); -} - -static GBytes* fl_mock_binary_messenger_send_on_channel_finish( - FlBinaryMessenger* messenger, - GAsyncResult* result, - GError** error) { - g_return_val_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger), nullptr); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - return self->mock->fl_binary_messenger_send_on_channel_finish(messenger, - result, error); -} - -static void fl_mock_binary_messenger_resize_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - int64_t new_size) { - g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger)); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - self->mock->fl_binary_messenger_resize_channel(messenger, channel, new_size); -} - -static void fl_mock_binary_messenger_set_warns_on_channel_overflow( - FlBinaryMessenger* messenger, - const gchar* channel, - bool warns) { - g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger)); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - self->mock->fl_binary_messenger_set_warns_on_channel_overflow(messenger, - channel, warns); -} - -static void fl_mock_binary_messenger_shutdown(FlBinaryMessenger* messenger) {} - -static void fl_mock_binary_messenger_iface_init( - FlBinaryMessengerInterface* iface) { - iface->set_message_handler_on_channel = - fl_mock_binary_messenger_set_message_handler_on_channel; - iface->send_response = fl_mock_binary_messenger_send_response; - iface->send_on_channel = fl_mock_binary_messenger_send_on_channel; - iface->send_on_channel_finish = - fl_mock_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; - iface->shutdown = fl_mock_binary_messenger_shutdown; -} - -static void fl_mock_binary_messenger_init(FlMockBinaryMessenger* self) {} diff --git a/shell/platform/linux/testing/mock_binary_messenger.h b/shell/platform/linux/testing/mock_binary_messenger.h deleted file mode 100644 index 394e55882ed2d..0000000000000 --- a/shell/platform/linux/testing/mock_binary_messenger.h +++ /dev/null @@ -1,91 +0,0 @@ -// 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_TESTING_MOCK_BINARY_MESSENGER_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_H_ - -#include - -#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" - -#include "gmock/gmock.h" - -namespace flutter { -namespace testing { - -// Mock for FlBinaryMessenger. -class MockBinaryMessenger { - public: - MockBinaryMessenger(); - ~MockBinaryMessenger(); - - // This was an existing use of operator overloading. It's against our style - // guide but enabling clang tidy on header files is a higher priority than - // fixing this. - // NOLINTNEXTLINE(google-explicit-constructor) - operator FlBinaryMessenger*(); - - MOCK_METHOD(void, - fl_binary_messenger_set_message_handler_on_channel, - (FlBinaryMessenger * messenger, - const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data, - GDestroyNotify destroy_notify)); - - MOCK_METHOD(gboolean, - fl_binary_messenger_send_response, - (FlBinaryMessenger * messenger, - FlBinaryMessengerResponseHandle* response_handle, - GBytes* response, - GError** error)); - - MOCK_METHOD(void, - fl_binary_messenger_send_on_channel, - (FlBinaryMessenger * messenger, - const gchar* channel, - GBytes* message, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data)); - - MOCK_METHOD(GBytes*, - fl_binary_messenger_send_on_channel_finish, - (FlBinaryMessenger * messenger, - GAsyncResult* result, - GError** error)); - - MOCK_METHOD(void, - fl_binary_messenger_resize_channel, - (FlBinaryMessenger * messenger, - const gchar* channel, - int64_t new_size)); - - MOCK_METHOD(void, - fl_binary_messenger_set_warns_on_channel_overflow, - (FlBinaryMessenger * messenger, - const gchar* channel, - bool warns)); - - bool HasMessageHandler(const gchar* channel) const; - - void SetMessageHandler(const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data); - - void ReceiveMessage(const gchar* channel, GBytes* message); - - private: - FlBinaryMessenger* instance_ = nullptr; - std::unordered_map - message_handlers_; - std::unordered_map - response_handles_; - std::unordered_map user_datas_; -}; - -} // namespace testing -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_H_ diff --git a/shell/platform/linux/testing/mock_binary_messenger_response_handle.cc b/shell/platform/linux/testing/mock_binary_messenger_response_handle.cc deleted file mode 100644 index 4bd7e419d2071..0000000000000 --- a/shell/platform/linux/testing/mock_binary_messenger_response_handle.cc +++ /dev/null @@ -1,25 +0,0 @@ -// 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/testing/mock_binary_messenger_response_handle.h" - -struct _FlMockBinaryMessengerResponseHandle { - FlBinaryMessengerResponseHandle parent_instance; -}; - -G_DEFINE_TYPE(FlMockBinaryMessengerResponseHandle, - fl_mock_binary_messenger_response_handle, - fl_binary_messenger_response_handle_get_type()); - -static void fl_mock_binary_messenger_response_handle_class_init( - FlMockBinaryMessengerResponseHandleClass* klass) {} - -static void fl_mock_binary_messenger_response_handle_init( - FlMockBinaryMessengerResponseHandle* self) {} - -FlMockBinaryMessengerResponseHandle* -fl_mock_binary_messenger_response_handle_new() { - return FL_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE( - g_object_new(fl_mock_binary_messenger_response_handle_get_type(), NULL)); -} diff --git a/shell/platform/linux/testing/mock_binary_messenger_response_handle.h b/shell/platform/linux/testing/mock_binary_messenger_response_handle.h deleted file mode 100644 index 42d86cc80fa9c..0000000000000 --- a/shell/platform/linux/testing/mock_binary_messenger_response_handle.h +++ /dev/null @@ -1,23 +0,0 @@ -// 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_TESTING_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE_H_ - -#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE(FlMockBinaryMessengerResponseHandle, - fl_mock_binary_messenger_response_handle, - FL, - MOCK_BINARY_MESSENGER_RESPONSE_HANDLE, - FlBinaryMessengerResponseHandle) - -FlMockBinaryMessengerResponseHandle* -fl_mock_binary_messenger_response_handle_new(); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE_H_ diff --git a/shell/vmservice/pubspec.yaml b/shell/vmservice/pubspec.yaml index 0580a7281b6f6..9d8b480b10df7 100644 --- a/shell/vmservice/pubspec.yaml +++ b/shell/vmservice/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 734c69e8486dc..617b8c4513781 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn @@ -221,6 +221,7 @@ optional("fontmgr_android") { deps = [ ":typeface_freetype", + ":typeface_proxy", "//flutter/third_party/expat", ] public = skia_ports_fontmgr_android_public @@ -513,6 +514,7 @@ optional("jpeg_decode") { optional("jpeg_encode") { enabled = skia_use_libjpeg_turbo_encode && !skia_use_ndk_images + public_defines = [ "SK_CODEC_ENCODES_JPEG" ] deps = [ "//flutter/third_party/libjpeg-turbo:libjpeg" ] public = skia_encode_jpeg_public @@ -537,22 +539,27 @@ optional("xps") { sources = skia_xps_sources } -optional("png_decode") { +optional("png_decode_libpng") { enabled = skia_use_libpng_decode public_defines = [ "SK_CODEC_DECODES_PNG", "SK_CODEC_DECODES_ICO", + "SK_CODEC_DECODES_PNG_WITH_LIBPNG", ] deps = [ "//flutter/third_party/libpng" ] - sources = [ "$_skia_root/src/codec/SkIcoCodec.cpp" ] - sources += skia_codec_png + sources = [ "$_skia_root/src/codec/SkIcoCodec.cpp" ] + skia_codec_png_base + + skia_codec_libpng_srcs } optional("png_encode") { enabled = skia_use_libpng_encode && !skia_use_ndk_images - public = skia_encode_png_public + public_defines = [ + "SK_CODEC_ENCODES_PNG", + "SK_CODEC_ENCODES_PNG_WITH_LIBPNG", + ] + public = skia_encode_png_public deps = [ "//flutter/third_party/libpng" ] sources = skia_encode_png_srcs } @@ -575,6 +582,7 @@ optional("webp_decode") { optional("webp_encode") { enabled = skia_use_libwebp_encode && !skia_use_ndk_images + public_defines = [ "SK_CODEC_ENCODES_WEBP" ] public = skia_encode_webp_public deps = [ "//flutter/third_party/libwebp" ] @@ -633,7 +641,7 @@ skia_component("skia") { ":hsw", ":jpeg_decode", ":ndk_images", - ":png_decode", + ":png_decode_libpng", ":webp_decode", ":wuffs", ":xml", diff --git a/skia/modules/canvaskit/BUILD.gn b/skia/modules/canvaskit/BUILD.gn index 72961860d8868..1a24c8ff2bc87 100644 --- a/skia/modules/canvaskit/BUILD.gn +++ b/skia/modules/canvaskit/BUILD.gn @@ -170,7 +170,10 @@ canvaskit_wasm_lib("canvaskit") { "-sFILESYSTEM=0", "-sMODULARIZE", "-sNO_EXIT_RUNTIME=1", - "-sINITIAL_MEMORY=128MB", + "-sINITIAL_MEMORY=32MB", + + # Grow memory by +100% i.e. double the size each time we run out of memory. + "-sMEMORY_GROWTH_GEOMETRIC_STEP=1.0", "-sWASM", "-sSTRICT=1", ] diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index d292cf87010a9..a97cfa1218fcf 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -24248,22 +24248,6 @@ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --------------------------------------------------------------------------------- -boringssl - -Copyright (c) 2023, Google LLC - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY @@ -24340,6 +24324,22 @@ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-------------------------------------------------------------------------------- +boringssl + +Copyright (c) 2024, Google LLC + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY @@ -32253,7 +32253,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice 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/+/df716eaa6ed2c4778cea0bcb449e023c7ccd3a73 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/1a28e6c86b09f1c83365f54388c32ed97c9e9b31 /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- diff --git a/sky/packages/sky_engine/pubspec.yaml b/sky/packages/sky_engine/pubspec.yaml index e0648ded011cd..40ef5d948eaeb 100644 --- a/sky/packages/sky_engine/pubspec.yaml +++ b/sky/packages/sky_engine/pubspec.yaml @@ -1,3 +1,3 @@ name: sky_engine environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 diff --git a/testing/benchmark/pubspec.yaml b/testing/benchmark/pubspec.yaml index c69c058628f43..3009b77b4a06a 100644 --- a/testing/benchmark/pubspec.yaml +++ b/testing/benchmark/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/testing/dart/codec_test.dart b/testing/dart/codec_test.dart index e21b099a8cee0..7d0a2a23d2758 100644 --- a/testing/dart/codec_test.dart +++ b/testing/dart/codec_test.dart @@ -252,6 +252,46 @@ void main() { imageData = (await image.toByteData())!; expect(imageData.getUint32(imageData.lengthInBytes - 4), 0x00000000); }); + + test( + 'Animated apng frame decode does not crash with invalid destination region', + () async { + final Uint8List data = File( + path.join('flutter', 'lib', 'ui', 'fixtures', 'out_of_bounds.apng'), + ).readAsBytesSync(); + + final ui.Codec codec = await ui.instantiateImageCodec(data); + try { + await codec.getNextFrame(); + fail('exception not thrown'); + } on Exception catch (e) { + if (impellerEnabled) { + expect(e.toString(), contains('Could not decompress image.')); + } else { + expect(e.toString(), contains('Codec failed')); + } + } + }); + + test( + 'Animated apng frame decode does not crash with invalid destination region and bounds wrapping', + () async { + final Uint8List data = File( + path.join('flutter', 'lib', 'ui', 'fixtures', 'out_of_bounds_wrapping.apng'), + ).readAsBytesSync(); + + final ui.Codec codec = await ui.instantiateImageCodec(data); + try { + await codec.getNextFrame(); + fail('exception not thrown'); + } on Exception catch (e) { + if (impellerEnabled) { + expect(e.toString(), contains('Could not decompress image.')); + } else { + expect(e.toString(), contains('Codec failed')); + } + } + }); } /// Returns a File handle to a file in the skia/resources directory. diff --git a/testing/dart/pubspec.yaml b/testing/dart/pubspec.yaml index 00920cf6c4be0..51b88d4c72cd1 100644 --- a/testing/dart/pubspec.yaml +++ b/testing/dart/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/testing/dart/semantics_test.dart b/testing/dart/semantics_test.dart index a5841e7d1d2fe..8b2f88921054c 100644 --- a/testing/dart/semantics_test.dart +++ b/testing/dart/semantics_test.dart @@ -22,7 +22,7 @@ void main() { }); // This must match the number of actions in lib/ui/semantics.dart - const int numSemanticsActions = 23; + const int numSemanticsActions = 24; test('SemanticsAction.values refers to all actions.', () async { expect(SemanticsAction.values.length, equals(numSemanticsActions)); for (int index = 0; index < numSemanticsActions; ++index) { diff --git a/testing/display_list_testing.cc b/testing/display_list_testing.cc index 748437341243a..b3c6fe65ba34e 100644 --- a/testing/display_list_testing.cc +++ b/testing/display_list_testing.cc @@ -8,6 +8,7 @@ #include #include "flutter/display_list/display_list.h" +#include "flutter/display_list/effects/dl_color_filters.h" #include "flutter/display_list/effects/dl_color_sources.h" #include "flutter/display_list/effects/dl_image_filters.h" @@ -443,12 +444,6 @@ void DisplayListStreamDispatcher::setColorSource(const DlColorSource* source) { } startl() << "setColorSource("; switch (source->type()) { - case DlColorSourceType::kColor: { - const DlColorColorSource* color_src = source->asColor(); - FML_DCHECK(color_src); - os_ << "DlColorColorSource(" << color_src->color() << ")"; - break; - } case DlColorSourceType::kImage: { const DlImageColorSource* image_src = source->asImage(); FML_DCHECK(image_src); diff --git a/testing/display_list_testing.h b/testing/display_list_testing.h index 9a707bb862beb..17cf01d0239ea 100644 --- a/testing/display_list_testing.h +++ b/testing/display_list_testing.h @@ -263,7 +263,6 @@ class DisplayListGeneralReceiver : public DlOpReceiver { case DlColorSourceType::kRuntimeEffect: RecordByType(DisplayListOpType::kSetRuntimeEffectColorSource); break; - case DlColorSourceType::kColor: case DlColorSourceType::kLinearGradient: case DlColorSourceType::kRadialGradient: case DlColorSourceType::kConicalGradient: diff --git a/testing/lsan_suppressions.txt b/testing/lsan_suppressions.txt index 25f507f67d610..52ad4c64ee8e8 100644 --- a/testing/lsan_suppressions.txt +++ b/testing/lsan_suppressions.txt @@ -50,12 +50,6 @@ leak:RefCountedTest_DebugChecks_Test::TestBody # and allow some tests to inspect contents. leak:*flutter/shell/platform/linux/testing/mock_engine.cc -# TODO(bdero): Fix FL leaks: https://github.com/flutter/flutter/issues/90155 -leak:*flutter/shell/platform/linux/fl_keyboard_handler_test.cc* -leak:*flutter/shell/platform/linux/fl_key_channel_responder_test.cc* -leak:*flutter/shell/platform/linux/fl_basic_message_channel_test.cc* -leak:fl_message_codec_decode_message - # TODO(bdero): https://github.com/flutter/flutter/issues/90156 # Unfortunately, realloc calls originating from g_realloc effectively obscure # the trace of the original allocation. Deeper investigation is required to diff --git a/testing/scenario_app/pubspec.yaml b/testing/scenario_app/pubspec.yaml index f729a481226f7..b720088b87369 100644 --- a/testing/scenario_app/pubspec.yaml +++ b/testing/scenario_app/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/testing/skia_gold_client/pubspec.yaml b/testing/skia_gold_client/pubspec.yaml index d0e133633eb53..6efc55b8c9180 100644 --- a/testing/skia_gold_client/pubspec.yaml +++ b/testing/skia_gold_client/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/testing/smoke_test_failure/pubspec.yaml b/testing/smoke_test_failure/pubspec.yaml index bfb5ab78aaaf5..d82f9e2cb56c5 100644 --- a/testing/smoke_test_failure/pubspec.yaml +++ b/testing/smoke_test_failure/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/testing/symbols/pubspec.yaml b/testing/symbols/pubspec.yaml index cd7e2c196baf9..ee16ae2772154 100644 --- a/testing/symbols/pubspec.yaml +++ b/testing/symbols/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/third_party/.gitignore b/third_party/.gitignore index 5bd42c1696fca..bf3e9d89a4d9d 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore @@ -1,6 +1,7 @@ # Ignore everything by default, as these come from gclient/DEPS. # We'll explicitly include the folders we want to track. /* +/boringssl/src # Include the .gitignore file itself and .clang-tidy. !.gitignore @@ -12,6 +13,7 @@ # Include folders that have hand-written code (not DEPS). !accessibility/ +!boringssl/ !canvaskit/ !spring_animation/ !test_shaders/ diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn new file mode 100644 index 0000000000000..acf5cacfdee00 --- /dev/null +++ b/third_party/boringssl/BUILD.gn @@ -0,0 +1,93 @@ +# Copyright 2014 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/android/config.gni") +import("//build/config/arm.gni") +import("//build/config/compiler/compiler.gni") +import("//build/config/sanitizers/sanitizers.gni") +import("//build_overrides/build.gni") +import("src/gen/sources.gni") + +# Config for us and everybody else depending on BoringSSL. +config("external_config") { + include_dirs = [ "src/include" ] + if (is_component_build) { + defines = [ "BORINGSSL_SHARED_LIBRARY" ] + } +} + +# The config used by the :boringssl component itself, and the fuzzer copies. +config("component_config") { + visibility = [ ":*" ] + configs = [ ":internal_config" ] + defines = [ "BORINGSSL_IMPLEMENTATION" ] + + cflags_c = [ "-std=c17" ] +} + +# This config is used by anything that consumes internal headers. Tests consume +# this rather than :component_config. +config("internal_config") { + visibility = [ ":*" ] + defines = [ + "OPENSSL_SMALL", + "OPENSSL_STATIC_ARMCAP", + ] + if (is_posix) { + defines += [ "_XOPEN_SOURCE=700" ] + } +} + +config("no_asm_config") { + visibility = [ ":*" ] + defines = [ "OPENSSL_NO_ASM" ] +} + +# TODO(crbug.com/42290535): Move Chromium's use of libpki to the public API and +# unexport pki_internal_headers. +all_sources = bcm_internal_headers + bcm_sources + crypto_internal_headers + + crypto_sources + ssl_internal_headers + ssl_sources + pki_sources +all_headers = crypto_headers + ssl_headers + pki_headers + pki_internal_headers + +if (is_msan) { + # MSan instrumentation is incompatible with assembly optimizations. + # BoringSSL's GAS-compatible assembly knows how to detect MSan, but the NASM + # assembly does not, so we check for MSan explicitly. + source_set("boringssl_asm") { + visibility = [ ":*" ] + public_configs = [ ":no_asm_config" ] + } +} else if (is_win && (current_cpu == "x86" || current_cpu == "x64")) { + # Windows' x86 and x86_64 assembly is built with NASM. + source_set("boringssl_asm") { + visibility = [ ":*" ] + public_configs = [ ":no_asm_config" ] + } +} else { + # All other targets use GAS-compatible assembler. BoringSSL's assembly files + # are all wrapped in processor checks for the corresponding target, so there + # is no need to add target conditions in the build. + source_set("boringssl_asm") { + visibility = [ ":*" ] + sources = rebase_path(bcm_sources_asm + crypto_sources_asm, ".", "src") + include_dirs = [ "src/include" ] + } +} + +source_set("boringssl") { + sources = rebase_path(all_sources, ".", "src") + public = rebase_path(all_headers, ".", "src") + + if (is_win) { + configs += [ ":no_asm_config" ] + } else { + deps = [ ":boringssl_asm" ] + } + + public_configs = [ ":external_config" ] + configs += [ ":component_config" ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] +} diff --git a/third_party/tonic/filesystem/filesystem/file.cc b/third_party/tonic/filesystem/filesystem/file.cc index c8436c89054a3..29bd77fd37041 100644 --- a/third_party/tonic/filesystem/filesystem/file.cc +++ b/third_party/tonic/filesystem/filesystem/file.cc @@ -5,6 +5,7 @@ #include "tonic/filesystem/filesystem/file.h" #include +#include #include #include diff --git a/third_party/tonic/filesystem/filesystem/file.h b/third_party/tonic/filesystem/filesystem/file.h index be83b0f952544..0e1aece1fe664 100644 --- a/third_party/tonic/filesystem/filesystem/file.h +++ b/third_party/tonic/filesystem/filesystem/file.h @@ -5,6 +5,7 @@ #ifndef FILESYSTEM_FILE_H_ #define FILESYSTEM_FILE_H_ +#include #include #include diff --git a/third_party/txt/src/skia/paragraph_skia.cc b/third_party/txt/src/skia/paragraph_skia.cc index b3521dd529515..38065e9c595b5 100644 --- a/third_party/txt/src/skia/paragraph_skia.cc +++ b/third_party/txt/src/skia/paragraph_skia.cc @@ -191,7 +191,7 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter { // rendering will be faster as it avoids software rasterization. A stroke // width of four was chosen by eyeballing the point at which the path // text looks good enough, with some room for error. - return (paint.getColorSource() && !paint.getColorSource()->asColor()) || + return paint.getColorSource() || (paint.getDrawStyle() == DlDrawStyle::kStroke && paint.getStrokeWidth() > 4); } diff --git a/third_party/web_locale_keymap/pubspec.yaml b/third_party/web_locale_keymap/pubspec.yaml index 646fbb3b96997..2c107b6f432c8 100644 --- a/third_party/web_locale_keymap/pubspec.yaml +++ b/third_party/web_locale_keymap/pubspec.yaml @@ -3,7 +3,7 @@ name: web_locale_keymap publish_to: none environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 dev_dependencies: test: ^1.21.7 diff --git a/third_party/web_test_fonts/pubspec.yaml b/third_party/web_test_fonts/pubspec.yaml index 2042ad239ca21..511f6d635435b 100644 --- a/third_party/web_test_fonts/pubspec.yaml +++ b/third_party/web_test_fonts/pubspec.yaml @@ -3,7 +3,7 @@ name: web_test_fonts publish_to: none environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 dev_dependencies: args: any diff --git a/third_party/web_unicode/pubspec.yaml b/third_party/web_unicode/pubspec.yaml index fd57811f90f19..f003c2e14bf83 100644 --- a/third_party/web_unicode/pubspec.yaml +++ b/third_party/web_unicode/pubspec.yaml @@ -3,7 +3,7 @@ name: web_unicode publish_to: none environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 dev_dependencies: args: any diff --git a/tools/android_lint/pubspec.yaml b/tools/android_lint/pubspec.yaml index ff929f14a07b6..8b07f881d01f5 100644 --- a/tools/android_lint/pubspec.yaml +++ b/tools/android_lint/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/api_check/pubspec.yaml b/tools/api_check/pubspec.yaml index dc35621348c89..e0818fbbf641e 100644 --- a/tools/api_check/pubspec.yaml +++ b/tools/api_check/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/build_bucket_golden_scraper/pubspec.yaml b/tools/build_bucket_golden_scraper/pubspec.yaml index 667717300ac55..27b77c79ae458 100644 --- a/tools/build_bucket_golden_scraper/pubspec.yaml +++ b/tools/build_bucket_golden_scraper/pubspec.yaml @@ -6,7 +6,7 @@ name: build_bucket_golden_scraper publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/clang_tidy/pubspec.yaml b/tools/clang_tidy/pubspec.yaml index bf9fa508f0f32..954f4c3a26fd4 100644 --- a/tools/clang_tidy/pubspec.yaml +++ b/tools/clang_tidy/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/clangd_check/pubspec.yaml b/tools/clangd_check/pubspec.yaml index 54fe7e7db938c..2225fe689919a 100644 --- a/tools/clangd_check/pubspec.yaml +++ b/tools/clangd_check/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/compare_goldens/pubspec.yaml b/tools/compare_goldens/pubspec.yaml index d606f86817571..34c6134958d92 100644 --- a/tools/compare_goldens/pubspec.yaml +++ b/tools/compare_goldens/pubspec.yaml @@ -3,7 +3,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/const_finder/pubspec.yaml b/tools/const_finder/pubspec.yaml index 6d27db30abf72..8f825732b99ec 100644 --- a/tools/const_finder/pubspec.yaml +++ b/tools/const_finder/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/dir_contents_diff/pubspec.yaml b/tools/dir_contents_diff/pubspec.yaml index 2e51ec4e0f894..a1b32abe95ad6 100644 --- a/tools/dir_contents_diff/pubspec.yaml +++ b/tools/dir_contents_diff/pubspec.yaml @@ -3,7 +3,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/engine_tool/pubspec.yaml b/tools/engine_tool/pubspec.yaml index fa42d1596614d..c413e5d9a9a70 100644 --- a/tools/engine_tool/pubspec.yaml +++ b/tools/engine_tool/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/gen_web_locale_keymap/pubspec.yaml b/tools/gen_web_locale_keymap/pubspec.yaml index 9493b5bf16614..da2a9ae5f98d7 100644 --- a/tools/gen_web_locale_keymap/pubspec.yaml +++ b/tools/gen_web_locale_keymap/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/githooks/pubspec.yaml b/tools/githooks/pubspec.yaml index f0c37a7273cc4..a06b0645bb177 100644 --- a/tools/githooks/pubspec.yaml +++ b/tools/githooks/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/gn b/tools/gn index 0fa741985a008..325b5cbece147 100755 --- a/tools/gn +++ b/tools/gn @@ -434,6 +434,10 @@ def to_gn_args(args): gn_args['enable_unittests'] = False # Skia GN args. + gn_args['skia_use_libpng_decode'] = True + gn_args['skia_use_libpng_encode'] = True + gn_args['skia_use_rust_png_decode'] = False + gn_args['skia_use_rust_png_encode'] = False gn_args['skia_use_dng_sdk'] = False # RAW image handling. gn_args['skia_enable_pdf'] = False # PDF handling. gn_args['skia_use_x11'] = False # Never add the X11 dependency (only takes effect on Linux). @@ -569,10 +573,6 @@ def to_gn_args(args): else: gn_args['enable_backtrace'] = False - # Overrides whether Boring SSL is compiled with system as. Only meaningful - # on Android. - gn_args['bssl_use_clang_integrated_as'] = True - if args.allow_deprecated_api_calls: gn_args['allow_deprecated_api_calls'] = args.allow_deprecated_api_calls diff --git a/tools/golden_tests_harvester/pubspec.yaml b/tools/golden_tests_harvester/pubspec.yaml index c512a9c1c4ca3..576000ab657d8 100644 --- a/tools/golden_tests_harvester/pubspec.yaml +++ b/tools/golden_tests_harvester/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/header_guard_check/pubspec.yaml b/tools/header_guard_check/pubspec.yaml index 7401a16826bf4..be89d61e2d289 100644 --- a/tools/header_guard_check/pubspec.yaml +++ b/tools/header_guard_check/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/licenses/pubspec.yaml b/tools/licenses/pubspec.yaml index caa66d7557619..1d215c599f489 100644 --- a/tools/licenses/pubspec.yaml +++ b/tools/licenses/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/path_ops/dart/pubspec.yaml b/tools/path_ops/dart/pubspec.yaml index 49e358c0d06e1..f6bec7bc1a196 100644 --- a/tools/path_ops/dart/pubspec.yaml +++ b/tools/path_ops/dart/pubspec.yaml @@ -6,7 +6,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/pkg/engine_build_configs/pubspec.yaml b/tools/pkg/engine_build_configs/pubspec.yaml index 369800c9d96dc..d3e29b99df4f8 100644 --- a/tools/pkg/engine_build_configs/pubspec.yaml +++ b/tools/pkg/engine_build_configs/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/pkg/engine_repo_tools/pubspec.yaml b/tools/pkg/engine_repo_tools/pubspec.yaml index 02c8262090b69..3b6bb295b457a 100644 --- a/tools/pkg/engine_repo_tools/pubspec.yaml +++ b/tools/pkg/engine_repo_tools/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/pkg/git_repo_tools/pubspec.yaml b/tools/pkg/git_repo_tools/pubspec.yaml index e01df70cf12bc..010a6c08569af 100644 --- a/tools/pkg/git_repo_tools/pubspec.yaml +++ b/tools/pkg/git_repo_tools/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/tools/pkg/process_fakes/pubspec.yaml b/tools/pkg/process_fakes/pubspec.yaml index f17791397b963..5db0814324c0f 100644 --- a/tools/pkg/process_fakes/pubspec.yaml +++ b/tools/pkg/process_fakes/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # Required for workspace support. environment: - sdk: ^3.5.0-294.0.dev + sdk: ^3.7.0-0 # This package is managed as part of the engine workspace. resolution: workspace diff --git a/vulkan/vulkan_surface.h b/vulkan/vulkan_surface.h index 3455425c27631..fafd90ab4be46 100644 --- a/vulkan/vulkan_surface.h +++ b/vulkan/vulkan_surface.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_VULKAN_VULKAN_SURFACE_H_ #define FLUTTER_VULKAN_VULKAN_SURFACE_H_ +#include + #include "flutter/fml/macros.h" #include "flutter/vulkan/procs/vulkan_handle.h" #include "third_party/skia/include/core/SkSize.h" diff --git a/web_sdk/pubspec.yaml b/web_sdk/pubspec.yaml index 08bb0a4331bf1..2d5ef8e63cd42 100644 --- a/web_sdk/pubspec.yaml +++ b/web_sdk/pubspec.yaml @@ -2,7 +2,7 @@ name: web_sdk_tests # Keep the SDK version range in sync with lib/web_ui/pubspec.yaml environment: - sdk: '>=3.6.0-0 <4.0.0' + sdk: ^3.7.0-0 dependencies: args: any # see dependency_overrides diff --git a/web_sdk/web_engine_tester/pubspec.yaml b/web_sdk/web_engine_tester/pubspec.yaml index 875fe7984cb2e..7b86604a1fb34 100644 --- a/web_sdk/web_engine_tester/pubspec.yaml +++ b/web_sdk/web_engine_tester/pubspec.yaml @@ -2,7 +2,7 @@ name: web_engine_tester # Keep the SDK version range in sync with lib/web_ui/pubspec.yaml environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 dependencies: js: ^0.7.0 diff --git a/web_sdk/web_test_utils/pubspec.yaml b/web_sdk/web_test_utils/pubspec.yaml index 0cd10a68cb915..245582bc9db72 100644 --- a/web_sdk/web_test_utils/pubspec.yaml +++ b/web_sdk/web_test_utils/pubspec.yaml @@ -2,7 +2,7 @@ name: web_test_utils # Keep the SDK version range in sync with lib/web_ui/pubspec.yaml environment: - sdk: '>=3.2.0-0 <4.0.0' + sdk: ^3.7.0-0 dependencies: collection: 1.17.0