diff --git a/.ci.yaml b/.ci.yaml index 68e0388d13d22..637d34341e5cd 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -264,7 +264,6 @@ targets: - name: Linux Web Engine recipe: engine/web_engine - bringup: true properties: add_recipes_cq: "true" cores: "32" diff --git a/.clang-tidy b/.clang-tidy index bbcce4fe1497e..abd87ed614c4f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,11 +4,17 @@ Checks: "bugprone-use-after-move,\ clang-analyzer-*,\ clang-diagnostic-*,\ +darwin-*,\ google-*,\ modernize-use-default-member-init,\ +objc-*,\ +-objc-nsinvocation-argument-lifetime,\ readability-identifier-naming,\ +-google-build-using-namespace,\ +-google-default-arguments,\ -google-objc-global-variable-declaration,\ -google-objc-avoid-throwing-exception,\ +-google-readability-casting,\ -clang-analyzer-nullability.NullPassedToNonnull,\ -clang-analyzer-nullability.NullablePassedToNonnull,\ -clang-analyzer-nullability.NullReturnedFromNonnull,\ @@ -16,23 +22,6 @@ readability-identifier-naming,\ performance-move-const-arg,\ performance-unnecessary-value-param" -# Only warnings treated as errors are reported -# in the "ci/lint.sh" script and pre-push git hook. -# Add checks when all warnings are fixed -# to prevent new warnings being introduced. -# https://github.com/flutter/flutter/issues/93279 -# Note: There are platform specific warnings as errors in -# //ci/lint.sh -WarningsAsErrors: "bugprone-use-after-move,\ -clang-analyzer-*,\ -readability-identifier-naming,\ -clang-diagnostic-*,\ -google-objc-*,\ -google-explicit-constructor,\ -google-readability-avoid-underscore-in-googletest-name,\ -performance-move-const-arg,\ -performance-unnecessary-value-param" - CheckOptions: - key: modernize-use-default-member-init.UseAssignment value: true diff --git a/DEPS b/DEPS index 0fd454e7665ea..9516a489f66b5 100644 --- a/DEPS +++ b/DEPS @@ -18,7 +18,7 @@ vars = { 'llvm_git': 'https://llvm.googlesource.com', # OCMock is for testing only so there is no google clone 'ocmock_git': 'https://github.com/erikdoe/ocmock.git', - 'skia_revision': '55f654bf5cff8eb8a5364725509204271100ca81', + 'skia_revision': 'c098e3c5d932798e0381ae452914e2658f20840c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. @@ -48,22 +48,23 @@ 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': 'c3f1b3642181003576afdab7547f9ed9a1eabe8c', + 'dart_revision': 'd2766b385c2a962be208ee51e03e8cfc20ef0351', # 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': 'ec53f4b2d5b0d52ae703c5b696ecf052ad5fffbb', 'dart_boringssl_gen_rev': 'ced85ef0a00bbca77ce5a91261a5f2ae61b1e62f', 'dart_boringssl_rev': '87f316d7748268eb56f2dc147bd593254ae93198', 'dart_browser_launcher_rev': '5fa0bd6cddc33785f43c920576fc03dcee1c3caa', 'dart_clock_rev': '8a8231fa7912d84c7e99236b7800cfbef5ea7ae5', 'dart_collection_rev': 'efd709fc1760a595f8575f4137a1847de1b49d76', 'dart_devtools_rev': '23444af89d716818f099974df3e4fffac87fd886', - 'dart_protobuf_rev': '4af1cb3c4e116d02d3b3d005fd9d4995fbc4c564', + 'dart_protobuf_rev': 'ae90e53cd690edbfc72fa6c293fdb7b4a09ee0a2', 'dart_pub_rev': '6ac42d7644dedfcc500147ab47886eecab4b1b38', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': '32591071a83f632478e702f67e29de6e54428ce9', - 'dart_webdev_rev': '22f6271c4ae362d7d13cfe14442aecb197140436', - 'dart_webkit_inspection_protocol_rev': 'b825c8f6a12200d619729903207ac826cce278da', + 'dart_webdev_rev': '3ec168f6815af9d5f11278111d147bc82c0755c3', + 'dart_webkit_inspection_protocol_rev': 'ddb624cd85954dd384056cc253a8fc2b9da5364d', 'dart_yaml_edit_rev': '299f74594ff9fda412c1da5c0b5d5231d0c6fc42', 'dart_zlib_rev': '27c2f474b71d0d20764f86f60ef8b00da1a16cda', @@ -179,6 +180,9 @@ deps = { # WARNING: Unused Dart dependencies in the list below till "WARNING:" marker are removed automatically - see create_updated_flutter_deps.py. + 'src/third_party/dart/third_party/binaryen/src': + Var('chromium_git') + '/external/github.com/WebAssembly/binaryen.git@ec53f4b2d5b0d52ae703c5b696ecf052ad5fffbb', + 'src/third_party/dart/third_party/devtools': {'packages': [{'version': 'git_revision:23444af89d716818f099974df3e4fffac87fd886', 'package': 'dart/third_party/flutter/devtools'}], 'dep_type': 'cipd'}, @@ -198,7 +202,7 @@ deps = { Var('dart_git') + '/browser_launcher.git' + '@' + Var('dart_browser_launcher_rev'), 'src/third_party/dart/third_party/pkg/cli_util': - Var('dart_git') + '/cli_util.git@b0adbba89442b2ea6fef39c7a82fe79cb31e1168', + Var('dart_git') + '/cli_util.git@edcf1c357dfc92f760ea0f1bbdb94f9b72d26b71', 'src/third_party/dart/third_party/pkg/clock': Var('dart_git') + '/clock.git' + '@' + Var('dart_clock_rev'), @@ -213,13 +217,13 @@ deps = { Var('dart_git') + '/crypto.git@bf0c33b42eb7e5991ee98429318884695e576c2b', 'src/third_party/dart/third_party/pkg/csslib': - Var('dart_git') + '/csslib.git@ba2eb2d80530eedefadaade338a09c2dd60410f3', + Var('dart_git') + '/csslib.git@34203c09f073ed8267f5d6e333daddb02e6ff609', 'src/third_party/dart/third_party/pkg/dart_style': Var('dart_git') + '/dart_style.git@f79a9828ad07e50d6e8352ac154cc16eb4d78d5c', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@08e309818acb44ba3dd46ed999bf6b0359c356ff', + Var('dart_git') + '/dartdoc.git@dc502d0862fe1ba8451c9c57cd7ab70432634af3', 'src/third_party/dart/third_party/pkg/ffi': Var('dart_git') + '/ffi.git@3ede2312dd6ec37db6e7bcd6e1236647f72c7fc0', @@ -237,7 +241,7 @@ deps = { Var('dart_git') + '/html.git@28fb8b97acf471bedcfa4eaf38899a0f65d5e30d', 'src/third_party/dart/third_party/pkg/http': - Var('dart_git') + '/http.git@63390263e230bbd0aa2dae286fd7a64098e09029', + Var('dart_git') + '/http.git@d56141de40b69e8ae3cc22602caea6cca3fba4dc', 'src/third_party/dart/third_party/pkg/http_multi_server': Var('dart_git') + '/http_multi_server.git@e31c6988e3869fb4019429254604066338f86095', @@ -255,22 +259,22 @@ deps = { Var('dart_git') + '/logging.git@f322480fb9d9e83e677c08db6d09067059f7ff74', 'src/third_party/dart/third_party/pkg/markdown': - Var('dart_git') + '/markdown.git@a70b93a1a004cc1da04a3e3ea59821ef8391e0d6', + Var('dart_git') + '/markdown.git@37951d151750acfae756b2e466f563c1c5119b3d', 'src/third_party/dart/third_party/pkg/matcher': - Var('dart_git') + '/matcher.git@6a9b83bbd73e50df2058b3e8e4aa301df49569c6', + Var('dart_git') + '/matcher.git@15d4af21002ae9adee952110192a3face96307c7', 'src/third_party/dart/third_party/pkg/mime': - Var('dart_git') + '/mime.git@d80f4d09067af87d84d9cb647acfa4d2d313d795', + Var('dart_git') + '/mime.git@c0c4c47a3d7bf696f1aa1959fb83d598baadb33c', 'src/third_party/dart/third_party/pkg/mockito': - Var('dart_git') + '/mockito.git@748e88e4cbf7e3acd1144cd8e3ea4ae87ea8c9c2', + Var('dart_git') + '/mockito.git@347d3e4cc64752b2ff7b5d35fe5cd1b281b17413', 'src/third_party/dart/third_party/pkg/package_config': - Var('dart_git') + '/package_config.git@cff98c90acc457a3b0750f0a7da0e351a35e5d0c', + Var('dart_git') + '/package_config.git@abb4aec904ab8c739b6dcec516d44f56d96c8115', 'src/third_party/dart/third_party/pkg/path': - Var('dart_git') + '/path.git@58ba22c53e40a05c407abb070ec63674b3a38c4d', + Var('dart_git') + '/path.git@12ce876fdd8873128671acfec54c8ad88da361fa', 'src/third_party/dart/third_party/pkg/pool': Var('dart_git') + '/pool.git@1ea5b031cfda37786d305292cb8104dffb45d9ae', @@ -285,7 +289,7 @@ deps = { Var('dart_git') + '/pub_semver.git@28159b8c5b96fc2709d0904389d7932880f68659', 'src/third_party/dart/third_party/pkg/shelf': - Var('dart_git') + '/shelf.git@5fd2593d47120232054ebcc794f3a028d903f1f8', + Var('dart_git') + '/shelf.git@1c2104737973715426035c11ba840c7f23d8f186', 'src/third_party/dart/third_party/pkg/source_map_stack_trace': Var('dart_git') + '/source_map_stack_trace.git@8d8078fcc81c8f7936805cd277198493e0b7fc62', @@ -309,13 +313,13 @@ deps = { Var('dart_git') + '/string_scanner.git@4a5cbc5c1127151ea507cc9da797b829857607e8', 'src/third_party/dart/third_party/pkg/term_glyph': - Var('dart_git') + '/term_glyph.git@ec7cf7bb51ebb7d55760a1359f6697690dbc06ba', + Var('dart_git') + '/term_glyph.git@822cd5b3418615c6db715a796c2c9ba9acb63b0d', 'src/third_party/dart/third_party/pkg/test': Var('dart_git') + '/test.git@7756833000d671d4540b37ef04acd4b9e716026f', 'src/third_party/dart/third_party/pkg/test_reflective_loader': - Var('dart_git') + '/test_reflective_loader.git@ef934b7a894d78601ba67d8f6207bd4505690456', + Var('dart_git') + '/test_reflective_loader.git@52b6753852661787208e003f9716b079026c7ac7', 'src/third_party/dart/third_party/pkg/typed_data': Var('dart_git') + '/typed_data.git@1e838b8ec85699b5b99e793d004ae315e72fcbc0', @@ -336,7 +340,7 @@ deps = { Var('dart_git') + '/external/github.com/google/webkit_inspection_protocol.dart.git' + '@' + Var('dart_webkit_inspection_protocol_rev'), 'src/third_party/dart/third_party/pkg/yaml': - Var('dart_git') + '/yaml.git@fda5b15692ccfa0feb7793a27fe3829b3d0f77fa', + Var('dart_git') + '/yaml.git@f6992752da8883a4bd9b036063371dca552848cc', 'src/third_party/dart/third_party/pkg/yaml_edit': Var('dart_git') + '/yaml_edit.git' + '@' + Var('dart_yaml_edit_rev'), @@ -692,7 +696,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'SVtX810D2U_ZgBcpxIHbGCVzRKBhya-WKNtZsMDQqIUC' + 'version': 'mwKdD1jX_KVP1U76zmZ_Ori2TmrLCU8_1j0OGYy1CNEC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', @@ -702,7 +706,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'JzUXGxIUUNgr8qJUxGxh_UnhZqEJmQC4TkW8zJPSh9MC' + 'version': '5Xd8MJTM-pWPWCgUaaVSPeXe3pAu-xZ-_VO3NgARPDEC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/bin/format.dart b/ci/bin/format.dart index 6c49016737f56..9f6674c1ef69a 100644 --- a/ci/bin/format.dart +++ b/ci/bin/format.dart @@ -71,7 +71,7 @@ FormatCheck nameToFormatCheck(String name) { String formatCheckToName(FormatCheck check) { switch (check) { case FormatCheck.clang: - return 'C++/ObjC'; + return 'C++/ObjC/Shader'; case FormatCheck.gn: return 'GN'; case FormatCheck.java: @@ -301,7 +301,7 @@ abstract class FormatChecker { } } -/// Checks and formats C++/ObjC files using clang-format. +/// Checks and formats C++/ObjC/Shader files using clang-format. class ClangFormatChecker extends FormatChecker { ClangFormatChecker({ ProcessManager processManager = const LocalProcessManager(), @@ -350,7 +350,7 @@ class ClangFormatChecker extends FormatChecker { @override Future fixFormatting() async { - message('Fixing C++/ObjC formatting...'); + message('Fixing C++/ObjC/Shader formatting...'); final List failures = await _getCFormatFailures(fixing: true); if (failures.isEmpty) { return true; @@ -365,7 +365,7 @@ class ClangFormatChecker extends FormatChecker { } Future> _getCFormatFailures({bool fixing = false}) async { - message('Checking C++/ObjC formatting...'); + message('Checking C++/ObjC/Shader formatting...'); const List clangFiletypes = [ '*.c', '*.cc', @@ -374,10 +374,17 @@ class ClangFormatChecker extends FormatChecker { '*.h', '*.m', '*.mm', + '*.glsl', + '*.hlsl', + '*.comp', + '*.tese', + '*.tesc', + '*.vert', + '*.frag', ]; final List files = await getFileList(clangFiletypes); if (files.isEmpty) { - message('No C++/ObjC files with changes, skipping C++/ObjC format check.'); + message('No C++/ObjC/Shader files with changes, skipping C++/ObjC/Shader format check.'); return []; } if (verbose) { @@ -416,10 +423,10 @@ class ClangFormatChecker extends FormatChecker { if (failed.isNotEmpty) { final bool plural = failed.length > 1; if (fixing) { - message('Fixing ${failed.length} C++/ObjC file${plural ? 's' : ''}' + message('Fixing ${failed.length} C++/ObjC/Shader file${plural ? 's' : ''}' ' which ${plural ? 'were' : 'was'} formatted incorrectly.'); } else { - error('Found ${failed.length} C++/ObjC file${plural ? 's' : ''}' + error('Found ${failed.length} C++/ObjC/Shader file${plural ? 's' : ''}' ' which ${plural ? 'were' : 'was'} formatted incorrectly.'); stdout.writeln('To fix, run:'); stdout.writeln(); @@ -431,7 +438,7 @@ class ClangFormatChecker extends FormatChecker { stdout.writeln(); } } else { - message('Completed checking ${diffJobs.length} C++/ObjC files with no formatting problems.'); + message('Completed checking ${diffJobs.length} C++/ObjC/Shader files with no formatting problems.'); } return failed.map((WorkerJob job) { return job.result.stdout; diff --git a/ci/licenses.sh b/ci/licenses.sh index d661acc12a554..f1b08f4ba8c60 100755 --- a/ci/licenses.sh +++ b/ci/licenses.sh @@ -121,7 +121,7 @@ function verify_licenses() ( local actualLicenseCount actualLicenseCount="$(tail -n 1 flutter/ci/licenses_golden/licenses_flutter | tr -dc '0-9')" - local expectedLicenseCount=16 # When changing this number: Update the error message below as well describing all expected license types. + local expectedLicenseCount=17 # When changing this number: Update the error message below as well describing all expected license types. if [[ $actualLicenseCount -ne $expectedLicenseCount ]]; then echo "=============================== ERROR ===============================" diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 00174c6fc11df..1cbe4bdeec8a7 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -613,6 +613,7 @@ LIBRARY: accessibility LIBRARY: engine LIBRARY: tonic LIBRARY: txt +LIBRARY: web_unicode ORIGIN: ../../../flutter/LICENSE TYPE: LicenseType.bsd FILE: ../../../flutter/.clang-tidy @@ -1121,6 +1122,7 @@ FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/branching.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/color.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/constants.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/gaussian.glsl +FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/gradient.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/texture.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/transform.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/types.glsl @@ -1142,10 +1144,10 @@ FILE: ../../../flutter/impeller/display_list/display_list_image_impeller.h FILE: ../../../flutter/impeller/display_list/display_list_playground.cc FILE: ../../../flutter/impeller/display_list/display_list_playground.h FILE: ../../../flutter/impeller/display_list/display_list_unittests.cc +FILE: ../../../flutter/impeller/display_list/display_list_vertices_geometry.cc +FILE: ../../../flutter/impeller/display_list/display_list_vertices_geometry.h FILE: ../../../flutter/impeller/display_list/nine_patch_converter.cc FILE: ../../../flutter/impeller/display_list/nine_patch_converter.h -FILE: ../../../flutter/impeller/display_list/vertices_converter.cc -FILE: ../../../flutter/impeller/display_list/vertices_converter.h FILE: ../../../flutter/impeller/docs/assets/launch-app.png FILE: ../../../flutter/impeller/docs/assets/read_frame_captures/image1.png FILE: ../../../flutter/impeller/docs/assets/read_frame_captures/image10.png @@ -1291,6 +1293,7 @@ FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.vert FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.frag FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.vert FILE: ../../../flutter/impeller/entity/shaders/morphology_filter.frag @@ -1299,6 +1302,7 @@ FILE: ../../../flutter/impeller/entity/shaders/position.vert FILE: ../../../flutter/impeller/entity/shaders/position_color.vert FILE: ../../../flutter/impeller/entity/shaders/position_uv.vert FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert FILE: ../../../flutter/impeller/entity/shaders/runtime_effect.vert @@ -1307,6 +1311,7 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/srgb_to_linear_filter.frag FILE: ../../../flutter/impeller/entity/shaders/srgb_to_linear_filter.vert FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert FILE: ../../../flutter/impeller/entity/shaders/tiled_texture_fill.frag @@ -1350,8 +1355,6 @@ FILE: ../../../flutter/impeller/geometry/type_traits.cc FILE: ../../../flutter/impeller/geometry/type_traits.h FILE: ../../../flutter/impeller/geometry/vector.cc FILE: ../../../flutter/impeller/geometry/vector.h -FILE: ../../../flutter/impeller/geometry/vertices.cc -FILE: ../../../flutter/impeller/geometry/vertices.h FILE: ../../../flutter/impeller/image/backends/skia/compressed_image_skia.cc FILE: ../../../flutter/impeller/image/backends/skia/compressed_image_skia.h FILE: ../../../flutter/impeller/image/compressed_image.cc @@ -1490,6 +1493,7 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/texture_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/vk.h +FILE: ../../../flutter/impeller/renderer/backend_features.h FILE: ../../../flutter/impeller/renderer/blit_command.cc FILE: ../../../flutter/impeller/renderer/blit_command.h FILE: ../../../flutter/impeller/renderer/blit_pass.cc @@ -1996,7 +2000,6 @@ FILE: ../../../flutter/lib/web_ui/lib/text.dart FILE: ../../../flutter/lib/web_ui/lib/tile_mode.dart FILE: ../../../flutter/lib/web_ui/lib/ui.dart FILE: ../../../flutter/lib/web_ui/lib/window.dart -FILE: ../../../flutter/lib/web_ui/tool/unicode_sync_script.dart FILE: ../../../flutter/runtime/dart_isolate.cc FILE: ../../../flutter/runtime/dart_isolate.h FILE: ../../../flutter/runtime/dart_isolate_group_data.cc @@ -2614,16 +2617,16 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBacki FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositorUnittests.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbedderExternalTextureUnittests.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbedderExternalTextureTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.mm -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponderUnittests.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponderTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h @@ -2636,7 +2639,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSur FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterKeyPrimaryResponder.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterKeyboardViewDelegate.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin.mm @@ -2677,7 +2680,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewC FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderUnittests.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/KeyCodeMap.g.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/KeyCodeMap_Internal.h @@ -3281,6 +3284,8 @@ FILE: ../../../flutter/third_party/txt/src/txt/platform_fuchsia.cc FILE: ../../../flutter/third_party/txt/src/txt/platform_linux.cc FILE: ../../../flutter/third_party/txt/src/txt/platform_mac.mm FILE: ../../../flutter/third_party/txt/src/txt/platform_windows.cc +FILE: ../../../flutter/third_party/web_unicode/lib/web_unicode.dart +FILE: ../../../flutter/third_party/web_unicode/tool/unicode_sync_script.dart FILE: ../../../flutter/vulkan/procs/vulkan_handle.cc FILE: ../../../flutter/vulkan/procs/vulkan_handle.h FILE: ../../../flutter/vulkan/procs/vulkan_interface.cc @@ -3699,4 +3704,59 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -Total license count: 16 + +==================================================================================================== +LIBRARY: web_unicode +ORIGIN: ../../../flutter/third_party/web_unicode/LICENSE +TYPE: LicenseType.unknown +FILE: ../../../flutter/third_party/web_unicode/lib/web_unicode/codegen/line_break_properties.dart +FILE: ../../../flutter/third_party/web_unicode/lib/web_unicode/codegen/word_break_properties.dart +---------------------------------------------------------------------------------------------------- +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +See Terms of Use +for definitions of Unicode Inc.’s Data Files and Software. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2022 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in https://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 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 THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. +==================================================================================================== +Total license count: 17 diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 4f3c008bc339a..7dec3f3bf1bff 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 59d567c3d34daea0483c25f25a49d32c +Signature: 01cfa71692e6ca29ff87e76e286b998b UNUSED LICENSES: @@ -1805,6 +1805,7 @@ FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/memory.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/source_location.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/version.h FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/msi.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/result.h FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/stream.h FILE: ../../../fuchsia/sdk/linux/pkg/zx/msi.cc FILE: ../../../fuchsia/sdk/linux/pkg/zx/stream.cc @@ -2016,6 +2017,7 @@ FILE: ../../../fuchsia/sdk/linux/pkg/sys_component_cpp_testing/scoped_child.cc FILE: ../../../fuchsia/sdk/linux/pkg/syslog_structured_backend/fuchsia_syslog.cc FILE: ../../../fuchsia/sdk/linux/pkg/syslog_structured_backend/include/lib/syslog/structured_backend/cpp/fuchsia_syslog.h FILE: ../../../fuchsia/sdk/linux/pkg/syslog_structured_backend/include/lib/syslog/structured_backend/fuchsia_syslog.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/status_string.cc ---------------------------------------------------------------------------------------------------- Copyright 2021 The Fuchsia Authors. All rights reserved. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 2fab3302f520d..ed2bb745e3a9c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 275f7cfce617c35e931f9a2d0694989f +Signature: b50042e33d2c3c1d6c6cf89266e8a205 UNUSED LICENSES: @@ -582,7 +582,7 @@ FILE: ../../../third_party/skia/experimental/sktext/editor/Texts.h FILE: ../../../third_party/skia/experimental/sktext/include/Interface.h FILE: ../../../third_party/skia/experimental/sktext/include/Text.h FILE: ../../../third_party/skia/experimental/sktext/include/Types.h -FILE: ../../../third_party/skia/experimental/sktext/samples/Text.cpp +FILE: ../../../third_party/skia/experimental/sktext/slides/Text.cpp FILE: ../../../third_party/skia/experimental/sktext/src/Line.cpp FILE: ../../../third_party/skia/experimental/sktext/src/Line.h FILE: ../../../third_party/skia/experimental/sktext/src/LogicalRun.cpp @@ -682,6 +682,7 @@ FILE: ../../../third_party/skia/infra/bots/assets/ios-dev-image-13.5/VERSION FILE: ../../../third_party/skia/infra/bots/assets/ios-dev-image-13.6/VERSION FILE: ../../../third_party/skia/infra/bots/assets/ios-dev-image-14.4/VERSION FILE: ../../../third_party/skia/infra/bots/assets/kubectl/VERSION +FILE: ../../../third_party/skia/infra/bots/assets/kubeval/VERSION FILE: ../../../third_party/skia/infra/bots/assets/linux_vulkan_sdk/VERSION FILE: ../../../third_party/skia/infra/bots/assets/lottie-samples/VERSION FILE: ../../../third_party/skia/infra/bots/assets/mesa_intel_driver_linux/VERSION @@ -702,6 +703,7 @@ FILE: ../../../third_party/skia/infra/bots/assets/valgrind/VERSION FILE: ../../../third_party/skia/infra/bots/assets/win_ninja/VERSION FILE: ../../../third_party/skia/infra/bots/assets/win_toolchain/VERSION FILE: ../../../third_party/skia/infra/bots/assets/xcode-11.4.1/VERSION +FILE: ../../../third_party/skia/infra/bots/assets/yq/VERSION FILE: ../../../third_party/skia/infra/bots/cfg.json FILE: ../../../third_party/skia/infra/bots/jobs.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-arm-OptimizeForSize-Android_NoPatch.json @@ -1021,8 +1023,8 @@ FILE: ../../../third_party/skia/modules/skparagraph/include/ParagraphStyle.h FILE: ../../../third_party/skia/modules/skparagraph/include/TextShadow.h FILE: ../../../third_party/skia/modules/skparagraph/include/TextStyle.h FILE: ../../../third_party/skia/modules/skparagraph/include/TypefaceFontProvider.h -FILE: ../../../third_party/skia/modules/skparagraph/samples/BUILD.bazel -FILE: ../../../third_party/skia/modules/skparagraph/samples/SampleParagraph.cpp +FILE: ../../../third_party/skia/modules/skparagraph/slides/BUILD.bazel +FILE: ../../../third_party/skia/modules/skparagraph/slides/ParagraphSlide.cpp FILE: ../../../third_party/skia/modules/skparagraph/src/BUILD.bazel FILE: ../../../third_party/skia/modules/skparagraph/src/Decorations.cpp FILE: ../../../third_party/skia/modules/skparagraph/src/Decorations.h @@ -1057,7 +1059,7 @@ FILE: ../../../third_party/skia/modules/skresources/include/BUILD.bazel FILE: ../../../third_party/skia/modules/skresources/src/BUILD.bazel FILE: ../../../third_party/skia/modules/sksg/BUILD.bazel FILE: ../../../third_party/skia/modules/sksg/include/BUILD.bazel -FILE: ../../../third_party/skia/modules/sksg/samples/BUILD.bazel +FILE: ../../../third_party/skia/modules/sksg/slides/BUILD.bazel FILE: ../../../third_party/skia/modules/sksg/src/BUILD.bazel FILE: ../../../third_party/skia/modules/skshaper/BUILD.bazel FILE: ../../../third_party/skia/modules/skshaper/include/BUILD.bazel @@ -3565,7 +3567,7 @@ FILE: ../../../third_party/skia/include/private/SkSLStatement.h FILE: ../../../third_party/skia/include/private/SkSLSymbol.h FILE: ../../../third_party/skia/include/private/SkSafe_math.h FILE: ../../../third_party/skia/include/utils/SkNoDrawCanvas.h -FILE: ../../../third_party/skia/modules/sksg/samples/SampleSVGPong.cpp +FILE: ../../../third_party/skia/modules/sksg/slides/SVGPongSlide.cpp FILE: ../../../third_party/skia/modules/skshaper/include/SkShaper.h FILE: ../../../third_party/skia/modules/skshaper/src/SkShaper_harfbuzz.cpp FILE: ../../../third_party/skia/modules/skshaper/src/SkShaper_primitive.cpp @@ -7677,6 +7679,8 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/GrBufferTransferRenderTask.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrBufferUpdateRenderTask.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrBufferUpdateRenderTask.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrImageInfo.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/GrSurfaceProxyView.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/TestFormatColorTypeCombination.h FILE: ../../../third_party/skia/src/gpu/ganesh/tessellate/PathTessellator.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/tessellate/PathTessellator.h FILE: ../../../third_party/skia/src/gpu/ganesh/tessellate/StrokeTessellator.cpp @@ -7754,6 +7758,8 @@ FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnCaps.cpp FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnCaps.h FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnCommandBuffer.cpp FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnCommandBuffer.h +FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnGraphicsPipeline.h FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnQueueManager.cpp FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnQueueManager.h FILE: ../../../third_party/skia/src/gpu/graphite/dawn/DawnResourceProvider.cpp diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 8c1c45fe2caba..db471e1a3f2fa 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: ec3a799e0dff31096626517f97cca9e0 +Signature: ab4df1b506a6efc07b023aa35f376009 UNUSED LICENSES: @@ -14108,6 +14108,8 @@ FILE: ../../../third_party/dart/runtime/vm/heap/gc_shared.cc FILE: ../../../third_party/dart/runtime/vm/heap/gc_shared.h FILE: ../../../third_party/dart/runtime/vm/heap/page.cc FILE: ../../../third_party/dart/runtime/vm/heap/page.h +FILE: ../../../third_party/dart/runtime/vm/heap/sampler.cc +FILE: ../../../third_party/dart/runtime/vm/heap/sampler.h FILE: ../../../third_party/dart/runtime/vm/instructions.cc FILE: ../../../third_party/dart/runtime/vm/kernel_test.cc FILE: ../../../third_party/dart/runtime/vm/malloc_hooks_riscv.cc @@ -14118,6 +14120,7 @@ FILE: ../../../third_party/dart/runtime/vm/simulator_x64.h FILE: ../../../third_party/dart/sdk/lib/_http/http_testing.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_dev_runtime/private/js_names.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_dev_runtime/private/runtime_metrics.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/js_runtime/lib/synced/load_library_priority.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_shared/lib/js_util_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_shared/lib/synced/embedded_names.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/ffi_native_finalizer_patch.dart @@ -14127,6 +14130,7 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/record_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/async_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/bool.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/class_id.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/convert_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/core_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/date_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/developer.dart diff --git a/ci/licenses_golden/tool_signature b/ci/licenses_golden/tool_signature index e7884ad2cb98d..3885dfddea68b 100644 --- a/ci/licenses_golden/tool_signature +++ b/ci/licenses_golden/tool_signature @@ -1,2 +1,2 @@ -Signature: ae1981a94872d143d802356ab0f1a35e +Signature: 027af91b165acaa447651bfca8c7c704 diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 79a3c4c27329f..f42f7240aa2fa 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -9,9 +9,11 @@ namespace flutter { -ImageFilterLayer::ImageFilterLayer(std::shared_ptr filter) +ImageFilterLayer::ImageFilterLayer(std::shared_ptr filter, + const SkPoint& offset) : CacheableContainerLayer( RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer), + offset_(offset), filter_(std::move(filter)), transformed_filter_(nullptr) {} @@ -20,11 +22,12 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { FML_DCHECK(prev); - if (NotEquals(filter_, prev->filter_)) { + if (NotEquals(filter_, prev->filter_) || offset_ != prev->offset_) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); } } + context->PushTransform(SkMatrix::Translate(offset_.fX, offset_.fY)); if (context->has_raster_cache()) { context->SetTransform( RasterCacheUtil::GetIntegralTransCTM(context->GetTransform())); @@ -47,6 +50,9 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { } void ImageFilterLayer::Preroll(PrerollContext* context) { + auto mutator = context->state_stack.save(); + mutator.translate(offset_); + Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); @@ -73,7 +79,8 @@ void ImageFilterLayer::Preroll(PrerollContext* context) { SkIRect filter_out_bounds; filter_->map_device_bounds(filter_in_bounds, SkMatrix::I(), filter_out_bounds); - child_bounds = SkRect::Make(filter_out_bounds); + child_bounds.set(filter_out_bounds); + child_bounds.offset(offset_); set_paint_bounds(child_bounds); @@ -92,6 +99,7 @@ void ImageFilterLayer::Paint(PaintContext& context) const { FML_DCHECK(needs_painting(context)); auto mutator = context.state_stack.save(); + mutator.translate(offset_); if (context.raster_cache) { // Always apply the integral transform in the presence of a raster cache diff --git a/flow/layers/image_filter_layer.h b/flow/layers/image_filter_layer.h index 894b5d2e98187..b8e64b8cc73ec 100644 --- a/flow/layers/image_filter_layer.h +++ b/flow/layers/image_filter_layer.h @@ -15,7 +15,8 @@ namespace flutter { class ImageFilterLayer : public CacheableContainerLayer { public: - explicit ImageFilterLayer(std::shared_ptr filter); + explicit ImageFilterLayer(std::shared_ptr filter, + const SkPoint& offset = SkPoint::Make(0, 0)); void Diff(DiffContext* context, const Layer* old_layer) override; @@ -24,6 +25,7 @@ class ImageFilterLayer : public CacheableContainerLayer { void Paint(PaintContext& context) const override; private: + SkPoint offset_; std::shared_ptr filter_; std::shared_ptr transformed_filter_; diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index 9cf39e2c5cceb..92b690a5bf3b2 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -114,6 +114,59 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) { EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list)); } +TEST_F(ImageFilterLayerTest, SimpleFilterWithOffset) { + const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f); + const SkRect initial_cull_rect = SkRect::MakeLTRB(0, 0, 100, 100); + const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); + const SkPath child_path = SkPath().addRect(child_bounds); + const SkPaint child_paint = SkPaint(SkColors::kYellow); + const SkPoint layer_offset = SkPoint::Make(5.5, 6.5); + auto dl_image_filter = std::make_shared( + SkMatrix(), DlImageSampling::kMipmapLinear); + auto mock_layer = std::make_shared(child_path, child_paint); + auto layer = + std::make_shared(dl_image_filter, layer_offset); + layer->Add(mock_layer); + + SkMatrix child_matrix = initial_transform; + child_matrix.preTranslate(layer_offset.fX, layer_offset.fY); + const SkRect child_rounded_bounds = + SkRect::MakeLTRB(10.5f, 12.5f, 26.5f, 28.5f); + + preroll_context()->state_stack.set_preroll_delegate(initial_cull_rect, + initial_transform); + layer->Preroll(preroll_context()); + EXPECT_EQ(layer->paint_bounds(), child_rounded_bounds); + EXPECT_EQ(layer->child_paint_bounds(), child_bounds); + EXPECT_TRUE(layer->needs_painting(paint_context())); + EXPECT_EQ(mock_layer->parent_matrix(), child_matrix); + EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(), + initial_cull_rect); + + DisplayListBuilder expected_builder; + /* ImageFilterLayer::Paint() */ { + expected_builder.save(); + { + expected_builder.translate(layer_offset.fX, layer_offset.fY); + DlPaint dl_paint; + dl_paint.setImageFilter(dl_image_filter.get()); + expected_builder.saveLayer(&child_bounds, &dl_paint); + { + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path, + DlPaint().setColor(DlColor::kYellow())); + } + } + expected_builder.restore(); + } + expected_builder.restore(); + } + auto expected_display_list = expected_builder.Build(); + + layer->Paint(display_list_paint_context()); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list)); +} + TEST_F(ImageFilterLayerTest, SimpleFilterBounds) { const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f); const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); diff --git a/flutter_frontend_server/pubspec.yaml b/flutter_frontend_server/pubspec.yaml index b4cbec70b3011..4f5bc2056d3fa 100644 --- a/flutter_frontend_server/pubspec.yaml +++ b/flutter_frontend_server/pubspec.yaml @@ -55,6 +55,8 @@ dependency_overrides: path: ../../third_party/dart/pkg/dev_compiler expect: path: ../../third_party/dart/pkg/expect + ffi: + path: ../../third_party/dart/third_party/pkg/ffi fixnum: path: ../../third_party/dart/third_party/pkg/fixnum front_end: diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 996ea68839355..7ff85c58429b5 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -18,7 +18,6 @@ #include "impeller/entity/contents/vertices_contents.h" #include "impeller/entity/geometry.h" #include "impeller/geometry/path_builder.h" -#include "impeller/geometry/vertices.h" namespace impeller { @@ -373,11 +372,9 @@ void Canvas::DrawTextFrame(const TextFrame& text_frame, GetCurrentPass().AddEntity(entity); } -void Canvas::DrawVertices(const Vertices& vertices, +void Canvas::DrawVertices(std::unique_ptr vertices, BlendMode blend_mode, Paint paint) { - auto geometry = Geometry::MakeVertices(vertices); - Entity entity; entity.SetTransformation(GetCurrentTransformation()); entity.SetStencilDepth(GetStencilDepth()); @@ -386,7 +383,7 @@ void Canvas::DrawVertices(const Vertices& vertices, if (paint.color_source.has_value()) { auto& source = paint.color_source.value(); auto contents = source(); - contents->SetGeometry(std::move(geometry)); + contents->SetGeometry(std::move(vertices)); contents->SetAlpha(paint.color.alpha); entity.SetContents(paint.WithFilters(std::move(contents), true)); } else { @@ -394,7 +391,7 @@ void Canvas::DrawVertices(const Vertices& vertices, std::make_shared(); contents->SetColor(paint.color); contents->SetBlendMode(blend_mode); - contents->SetGeometry(std::move(geometry)); + contents->SetGeometry(std::move(vertices)); entity.SetContents(paint.WithFilters(std::move(contents), true)); } diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 7638c888b4b34..456948b99139c 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -14,11 +14,11 @@ #include "impeller/aiks/paint.h" #include "impeller/aiks/picture.h" #include "impeller/entity/entity_pass.h" +#include "impeller/entity/geometry.h" #include "impeller/geometry/matrix.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" #include "impeller/geometry/vector.h" -#include "impeller/geometry/vertices.h" #include "impeller/renderer/sampler_descriptor.h" #include "impeller/typographer/glyph_atlas.h" #include "impeller/typographer/text_frame.h" @@ -97,7 +97,7 @@ class Canvas { Point position, const Paint& paint); - void DrawVertices(const Vertices& vertices, + void DrawVertices(std::unique_ptr vertices, BlendMode blend_mode, Paint paint); diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 8ce9f4f233b49..d2708052d1838 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -202,7 +202,6 @@ using Shader = {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader; // Sanity checks for {{def.name}} {% if last(def.members).array_elements == 0 %} static_assert(std::is_standard_layout_v>); -static_assert(sizeof(Shader::{{def.name}}<0>) == {{def.byte_length}}); {% for member in def.members %} static_assert(offsetof(Shader::{{def.name}}<0>, {{member.name}}) == {{member.offset}}); {% endfor %} diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index daf0a6e878fc3..c8fe2f3890404 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -45,10 +45,14 @@ 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) { - sl_options.version = 100; + sl_options.version = source_options.gles_language_version > 0 + ? source_options.gles_language_version + : 100; sl_options.es = true; } else { - sl_options.version = 120; + sl_options.version = source_options.gles_language_version > 0 + ? source_options.gles_language_version + : 120; sl_options.es = false; } gl_compiler->set_common_options(sl_options); diff --git a/impeller/compiler/impellerc_main.cc b/impeller/compiler/impellerc_main.cc index 569b0006c07c0..f25ecd3f86509 100644 --- a/impeller/compiler/impellerc_main.cc +++ b/impeller/compiler/impellerc_main.cc @@ -73,6 +73,7 @@ bool Main(const fml::CommandLine& command_line) { switches.source_file_name, options.type, options.source_language, switches.entry_point); options.json_format = switches.json_format; + options.gles_language_version = switches.gles_language_version; Reflector::Options reflector_options; reflector_options.target_platform = switches.target_platform; diff --git a/impeller/compiler/shader_lib/impeller/BUILD.gn b/impeller/compiler/shader_lib/impeller/BUILD.gn index 5d7e85c6bd009..99ca69f472f7c 100644 --- a/impeller/compiler/shader_lib/impeller/BUILD.gn +++ b/impeller/compiler/shader_lib/impeller/BUILD.gn @@ -9,6 +9,7 @@ copy("impeller") { "color.glsl", "constants.glsl", "gaussian.glsl", + "gradient.glsl", "texture.glsl", "transform.glsl", "types.glsl", diff --git a/impeller/compiler/shader_lib/impeller/gradient.glsl b/impeller/compiler/shader_lib/impeller/gradient.glsl new file mode 100644 index 0000000000000..2c64edd35098b --- /dev/null +++ b/impeller/compiler/shader_lib/impeller/gradient.glsl @@ -0,0 +1,24 @@ +// 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 GRADIENT_GLSL_ +#define GRADIENT_GLSL_ + +#include + +/// Compute the indexes and mix coefficient used to mix colors for an +/// arbitrarily sized color gradient. +/// +/// The returned values are the lower index, upper index, and mix +/// coefficient. +vec3 IPComputeFixedGradientValues(float t, float colors_length) { + float rough_index = (colors_length - 1) * t; + float lower_index = floor(rough_index); + float upper_index = ceil(rough_index); + float scale = rough_index - lower_index; + + return vec3(lower_index, upper_index, scale); +} + +#endif diff --git a/impeller/compiler/shader_lib/impeller/texture.glsl b/impeller/compiler/shader_lib/impeller/texture.glsl index 447bedc22158d..d478a3a268cca 100644 --- a/impeller/compiler/shader_lib/impeller/texture.glsl +++ b/impeller/compiler/shader_lib/impeller/texture.glsl @@ -24,8 +24,12 @@ vec4 IPSample(sampler2D texture_sampler, vec2 coords, float y_coord_scale) { /// If `y_coord_scale` < 0.0, the Y coordinate is flipped. This is useful /// for Impeller graphics backends that use a flipped framebuffer coordinate /// space. -/// The range of `coods` will be mapped from [0, 1] to [half_texel, 1 - half_texel] -vec4 IPSampleLinear(sampler2D texture_sampler, vec2 coords, float y_coord_scale, vec2 half_texel) { +/// The range of `coods` will be mapped from [0, 1] to [half_texel, 1 - +/// half_texel] +vec4 IPSampleLinear(sampler2D texture_sampler, + vec2 coords, + float y_coord_scale, + vec2 half_texel) { coords.x = mix(half_texel.x, 1 - half_texel.x, coords.x); coords.y = mix(half_texel.y, 1 - half_texel.y, coords.y); return IPSample(texture_sampler, coords, y_coord_scale); @@ -79,7 +83,8 @@ vec4 IPSampleWithTileMode(sampler2D tex, return vec4(0); } - return IPSample(tex, IPVec2Tile(coords, x_tile_mode, y_tile_mode), y_coord_scale); + return IPSample(tex, IPVec2Tile(coords, x_tile_mode, y_tile_mode), + y_coord_scale); } /// Sample a texture, emulating a specific tile mode. @@ -97,7 +102,8 @@ vec4 IPSampleWithTileMode(sampler2D tex, /// /// This is useful for Impeller graphics backend that don't have native support /// for Decal. -/// The range of `coods` will be mapped from [0, 1] to [half_texel, 1 - half_texel] +/// The range of `coods` will be mapped from [0, 1] to [half_texel, 1 - +/// half_texel] vec4 IPSampleLinearWithTileMode(sampler2D tex, vec2 coords, float y_coord_scale, @@ -109,20 +115,23 @@ vec4 IPSampleLinearWithTileMode(sampler2D tex, return vec4(0); } - return IPSampleLinear(tex, IPVec2Tile(coords, x_tile_mode, y_tile_mode), y_coord_scale, half_texel); + return IPSampleLinear(tex, IPVec2Tile(coords, x_tile_mode, y_tile_mode), + y_coord_scale, half_texel); } /// Sample a texture, emulating a specific tile mode. /// /// This is useful for Impeller graphics backend that don't have native support /// for Decal. -/// The range of `coods` will be mapped from [0, 1] to [half_texel, 1 - half_texel] +/// The range of `coods` will be mapped from [0, 1] to [half_texel, 1 - +/// half_texel] vec4 IPSampleLinearWithTileMode(sampler2D tex, vec2 coords, float y_coord_scale, vec2 half_texel, float tile_mode) { - return IPSampleLinearWithTileMode(tex, coords, y_coord_scale, half_texel, tile_mode, tile_mode); + return IPSampleLinearWithTileMode(tex, coords, y_coord_scale, half_texel, + tile_mode, tile_mode); } #endif diff --git a/impeller/compiler/shader_lib/impeller/transform.glsl b/impeller/compiler/shader_lib/impeller/transform.glsl index f4ee335286dbd..444419db4b087 100644 --- a/impeller/compiler/shader_lib/impeller/transform.glsl +++ b/impeller/compiler/shader_lib/impeller/transform.glsl @@ -13,22 +13,16 @@ vec2 IPVec2TransformPosition(mat4 matrix, vec2 point) { // Returns the transformed gl_Position for a given glyph position in a glyph // atlas. -vec4 IPPositionForGlyphPosition(mat4 mvp, vec2 unit_vertex, vec2 glyph_position, vec2 glyph_size) { - vec4 translate = mvp[0] * glyph_position.x - + mvp[1] * glyph_position.y - + mvp[3]; - mat4 translated_mvp = mat4( - mvp[0], - mvp[1], - mvp[2], - vec4( - translate.xyz, - mvp[3].w - ) - ); - return translated_mvp * - vec4(unit_vertex.x * glyph_size.x, - unit_vertex.y * glyph_size.y, 0.0, 1.0); +vec4 IPPositionForGlyphPosition(mat4 mvp, + vec2 unit_position, + vec2 glyph_position, + vec2 glyph_size) { + vec4 translate = + mvp[0] * glyph_position.x + mvp[1] * glyph_position.y + mvp[3]; + mat4 translated_mvp = + mat4(mvp[0], mvp[1], mvp[2], vec4(translate.xyz, mvp[3].w)); + return translated_mvp * vec4(unit_position.x * glyph_size.x, + unit_position.y * glyph_size.y, 0.0, 1.0); } #endif diff --git a/impeller/compiler/shader_lib/impeller/types.glsl b/impeller/compiler/shader_lib/impeller/types.glsl index d896c5e60659a..87c7eee666c69 100644 --- a/impeller/compiler/shader_lib/impeller/types.glsl +++ b/impeller/compiler/shader_lib/impeller/types.glsl @@ -5,6 +5,21 @@ #ifndef TYPES_GLSL_ #define TYPES_GLSL_ +#extension GL_AMD_gpu_shader_half_float : enable + +#ifndef IMPELLER_TARGET_METAL + +precision mediump sampler2D; +precision mediump float; + +#define float16_t float +#define f16vec2 vec2 +#define f16vec3 vec3 +#define f16vec4 vec4 +#define f16mat4 mat4 + +#endif // IMPELLER_TARGET_METAL + #define BoolF float #define BoolV2 vec2 #define BoolV3 vec3 diff --git a/impeller/compiler/source_options.h b/impeller/compiler/source_options.h index 921ee5cb5c494..ccd264562a3d0 100644 --- a/impeller/compiler/source_options.h +++ b/impeller/compiler/source_options.h @@ -24,6 +24,7 @@ struct SourceOptions { std::vector include_dirs; std::string file_name = "main.glsl"; std::string entry_point_name = "main"; + uint32_t gles_language_version = 100; std::vector defines; bool json_format = false; diff --git a/impeller/compiler/switches.cc b/impeller/compiler/switches.cc index b816796552675..348b6eac31336 100644 --- a/impeller/compiler/switches.cc +++ b/impeller/compiler/switches.cc @@ -69,6 +69,7 @@ void Switches::PrintHelp(std::ostream& stream) { stream << "[optional,multiple] --include=" << std::endl; stream << "[optional,multiple] --define=" << std::endl; stream << "[optional] --depfile=" << std::endl; + stream << "[optional] --gles-language-verision=" << std::endl; stream << "[optional] --json" << std::endl; } @@ -124,6 +125,9 @@ Switches::Switches(const fml::CommandLine& command_line) command_line.GetOptionValueWithDefault("reflection-cc", "")), depfile_path(command_line.GetOptionValueWithDefault("depfile", "")), json_format(command_line.HasOption("json")), + gles_language_version( + stoi(command_line.GetOptionValueWithDefault("gles-language-version", + "0"))), entry_point( command_line.GetOptionValueWithDefault("entry-point", "main")) { if (!working_directory || !working_directory->is_valid()) { diff --git a/impeller/compiler/switches.h b/impeller/compiler/switches.h index 7a62861fcaf71..01774285e7f27 100644 --- a/impeller/compiler/switches.h +++ b/impeller/compiler/switches.h @@ -33,6 +33,7 @@ struct Switches { std::vector defines; bool json_format; SourceLanguage source_language = SourceLanguage::kUnknown; + uint32_t gles_language_version; std::string entry_point; Switches(); diff --git a/impeller/display_list/BUILD.gn b/impeller/display_list/BUILD.gn index a6c4fcd60e13b..48cf0f1619f38 100644 --- a/impeller/display_list/BUILD.gn +++ b/impeller/display_list/BUILD.gn @@ -10,10 +10,10 @@ impeller_component("display_list") { "display_list_dispatcher.h", "display_list_image_impeller.cc", "display_list_image_impeller.h", + "display_list_vertices_geometry.cc", + "display_list_vertices_geometry.h", "nine_patch_converter.cc", "nine_patch_converter.h", - "vertices_converter.cc", - "vertices_converter.h", ] public_deps = [ diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index a5fe27bb24aca..eba5782e43b22 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -20,8 +20,8 @@ #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "impeller/display_list/display_list_image_impeller.h" +#include "impeller/display_list/display_list_vertices_geometry.h" #include "impeller/display_list/nine_patch_converter.h" -#include "impeller/display_list/vertices_converter.h" #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/entity/contents/linear_gradient_contents.h" @@ -35,7 +35,6 @@ #include "impeller/geometry/path_builder.h" #include "impeller/geometry/scalar.h" #include "impeller/geometry/sigma.h" -#include "impeller/geometry/vertices.h" #include "impeller/renderer/formats.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" @@ -1104,7 +1103,8 @@ void DisplayListDispatcher::drawSkVertices(const sk_sp vertices, // |flutter::Dispatcher| void DisplayListDispatcher::drawVertices(const flutter::DlVertices* vertices, flutter::DlBlendMode dl_mode) { - canvas_.DrawVertices(ToVertices(vertices), ToBlendMode(dl_mode), paint_); + canvas_.DrawVertices(DLVerticesGeometry::MakeVertices(vertices), + ToBlendMode(dl_mode), paint_); } // |flutter::Dispatcher| diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index 91e886316598d..6b904e974a822 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -1054,5 +1054,71 @@ TEST_P(DisplayListTest, MaskBlursApplyCorrectlyToColorSources) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(DisplayListTest, DrawVerticesSolidColorTrianglesWithoutIndices) { + std::vector positions = {SkPoint::Make(100, 300), + SkPoint::Make(200, 100), + SkPoint::Make(300, 300)}; + std::vector colors = {flutter::DlColor::kWhite(), + flutter::DlColor::kGreen(), + flutter::DlColor::kWhite()}; + + auto vertices = flutter::DlVertices::Make( + flutter::DlVertexMode::kTriangles, 3, positions.data(), + /*texture_coorindates=*/nullptr, colors.data()); + + flutter::DisplayListBuilder builder; + flutter::DlPaint paint; + + paint.setColor(flutter::DlColor::kRed().modulateOpacity(0.5)); + builder.drawVertices(vertices, flutter::DlBlendMode::kSrcOver, paint); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(DisplayListTest, DrawVerticesLinearGradientWithoutIndices) { + std::vector positions = {SkPoint::Make(100, 300), + SkPoint::Make(200, 100), + SkPoint::Make(300, 300)}; + + auto vertices = flutter::DlVertices::Make( + flutter::DlVertexMode::kTriangles, 3, positions.data(), + /*texture_coorindates=*/nullptr, /*colors=*/nullptr); + + std::vector colors = {flutter::DlColor::kBlue(), + flutter::DlColor::kRed()}; + const float stops[2] = {0.0, 1.0}; + + auto linear = flutter::DlColorSource::MakeLinear( + {100.0, 100.0}, {300.0, 300.0}, 2, colors.data(), stops, + flutter::DlTileMode::kRepeat); + + flutter::DisplayListBuilder builder; + flutter::DlPaint paint; + + paint.setColorSource(linear); + builder.drawVertices(vertices, flutter::DlBlendMode::kSrcOver, paint); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(DisplayListTest, DrawVerticesSolidColorTrianglesWithIndices) { + std::vector positions = { + SkPoint::Make(100, 300), SkPoint::Make(200, 100), SkPoint::Make(300, 300), + SkPoint::Make(200, 500)}; + std::vector indices = {0, 1, 2, 0, 2, 3}; + + auto vertices = flutter::DlVertices::Make( + flutter::DlVertexMode::kTriangles, 6, positions.data(), + /*texture_coorindates=*/nullptr, /*colors=*/nullptr, 6, indices.data()); + + flutter::DisplayListBuilder builder; + flutter::DlPaint paint; + + paint.setColor(flutter::DlColor::kWhite()); + builder.drawVertices(vertices, flutter::DlBlendMode::kSrcOver, paint); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/display_list/display_list_vertices_geometry.cc b/impeller/display_list/display_list_vertices_geometry.cc new file mode 100644 index 0000000000000..1cab24c1fb861 --- /dev/null +++ b/impeller/display_list/display_list_vertices_geometry.cc @@ -0,0 +1,247 @@ +// 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/display_list/display_list_vertices_geometry.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/entity/position_color.vert.h" +#include "impeller/geometry/matrix.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/geometry/point.h" +#include "impeller/renderer/device_buffer.h" +#include "impeller/renderer/render_pass.h" +#include "third_party/skia/include/core/SkPoint.h" +#include "third_party/skia/include/core/SkRect.h" + +namespace impeller { + +static Rect ToRect(const SkRect& rect) { + return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); +} + +// Fan mode isn't natively supported. Unroll into triangle mode by +// manipulating the index array. +// +// In Triangle fan, the first vertex is shared across all triangles, and then +// each sliding window of two vertices plus that first vertex defines a +// triangle. +static std::vector fromFanIndices( + const flutter::DlVertices* vertices) { + FML_DCHECK(vertices->vertex_count() >= 3); + FML_DCHECK(vertices->mode() == flutter::DlVertexMode::kTriangleFan); + + std::vector indices; + + // Un-fan index buffer if provided. + if (vertices->index_count() > 0) { + auto* dl_indices = vertices->indices(); + auto center_point = dl_indices[0]; + for (int i = 1; i < vertices->index_count() - 1; i++) { + indices.push_back(center_point); + indices.push_back(dl_indices[i]); + indices.push_back(dl_indices[i + 1]); + } + } else { + // If indices were not provided, create an index buffer that unfans + // triangles instead of re-writing points, colors, et cetera. + for (int i = 1; i < vertices->vertex_count() - 1; i++) { + indices.push_back(0); + indices.push_back(i); + indices.push_back(i + 1); + } + } + return indices; +} + +/////// Vertices Geometry /////// + +// static +std::unique_ptr DLVerticesGeometry::MakeVertices( + const flutter::DlVertices* vertices) { + return std::make_unique(vertices); +} + +DLVerticesGeometry::DLVerticesGeometry(const flutter::DlVertices* vertices) + : vertices_(vertices) { + NormalizeIndices(); +} + +DLVerticesGeometry::~DLVerticesGeometry() = default; + +void DLVerticesGeometry::NormalizeIndices() { + // Convert triangle fan if present. + if (vertices_->mode() == flutter::DlVertexMode::kTriangleFan) { + normalized_indices_ = fromFanIndices(vertices_); + return; + } + + auto index_count = vertices_->index_count(); + auto vertex_count = vertices_->vertex_count(); + if (index_count != 0 || vertex_count == 0) { + return; + } + normalized_indices_.reserve(vertex_count); + for (auto i = 0; i < vertex_count; i++) { + normalized_indices_.push_back(i); + } +} + +static PrimitiveType GetPrimitiveType(const flutter::DlVertices* vertices) { + switch (vertices->mode()) { + case flutter::DlVertexMode::kTriangles: + return PrimitiveType::kTriangle; + case flutter::DlVertexMode::kTriangleStrip: + return PrimitiveType::kTriangleStrip; + case flutter::DlVertexMode::kTriangleFan: + // Unrolled into triangle mode. + return PrimitiveType::kTriangle; + } +} + +GeometryResult DLVerticesGeometry::GetPositionBuffer( + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + auto index_count = normalized_indices_.size() == 0 + ? vertices_->index_count() + : normalized_indices_.size(); + auto vertex_count = vertices_->vertex_count(); + auto* dl_indices = normalized_indices_.size() == 0 + ? vertices_->indices() + : normalized_indices_.data(); + auto* dl_vertices = vertices_->vertices(); + + size_t total_vtx_bytes = vertex_count * sizeof(float) * 2; + size_t total_idx_bytes = index_count * sizeof(uint16_t); + + DeviceBufferDescriptor buffer_desc; + buffer_desc.size = total_vtx_bytes + total_idx_bytes; + buffer_desc.storage_mode = StorageMode::kHostVisible; + + auto buffer = + renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc); + + if (!buffer->CopyHostBuffer(reinterpret_cast(dl_vertices), + Range{0, total_vtx_bytes}, 0)) { + return {}; + } + if (!buffer->CopyHostBuffer( + reinterpret_cast(const_cast(dl_indices)), + Range{0, total_idx_bytes}, total_vtx_bytes)) { + return {}; + } + + return GeometryResult{ + .type = GetPrimitiveType(vertices_), + .vertex_buffer = + { + .vertex_buffer = {.buffer = buffer, + .range = Range{0, total_vtx_bytes}}, + .index_buffer = {.buffer = buffer, + .range = + Range{total_vtx_bytes, total_idx_bytes}}, + .index_count = index_count, + .index_type = IndexType::k16bit, + }, + .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(), + .prevent_overdraw = false, + }; +} + +GeometryResult DLVerticesGeometry::GetPositionColorBuffer( + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass, + Color paint_color, + BlendMode blend_mode) { + using VS = GeometryColorPipeline::VertexShader; + + auto index_count = normalized_indices_.size() == 0 + ? vertices_->index_count() + : normalized_indices_.size(); + auto vertex_count = vertices_->vertex_count(); + auto* dl_indices = normalized_indices_.size() == 0 + ? vertices_->indices() + : normalized_indices_.data(); + auto* dl_vertices = vertices_->vertices(); + auto* dl_colors = vertices_->colors(); + + std::vector vertex_data(vertex_count); + { + for (auto i = 0; i < vertex_count; i++) { + auto dl_color = dl_colors[i]; + auto pre_color = Color(dl_color.getRedF(), dl_color.getGreenF(), + dl_color.getBlueF(), dl_color.getAlphaF()); + auto color = Color::BlendColor(paint_color, pre_color, blend_mode); + auto sk_point = dl_vertices[i]; + vertex_data[i] = { + .position = Point(sk_point.x(), sk_point.y()), + .color = color, + }; + } + } + + size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData); + size_t total_idx_bytes = index_count * sizeof(uint16_t); + + DeviceBufferDescriptor buffer_desc; + buffer_desc.size = total_vtx_bytes + total_idx_bytes; + buffer_desc.storage_mode = StorageMode::kHostVisible; + + auto buffer = + renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc); + + if (!buffer->CopyHostBuffer(reinterpret_cast(vertex_data.data()), + Range{0, total_vtx_bytes}, 0)) { + return {}; + } + if (!buffer->CopyHostBuffer( + reinterpret_cast(const_cast(dl_indices)), + Range{0, total_idx_bytes}, total_vtx_bytes)) { + return {}; + } + + return GeometryResult{ + .type = GetPrimitiveType(vertices_), + .vertex_buffer = + { + .vertex_buffer = {.buffer = buffer, + .range = Range{0, total_vtx_bytes}}, + .index_buffer = {.buffer = buffer, + .range = + Range{total_vtx_bytes, total_idx_bytes}}, + .index_count = index_count, + .index_type = IndexType::k16bit, + }, + .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(), + .prevent_overdraw = false, + }; +} + +GeometryResult DLVerticesGeometry::GetPositionUVBuffer( + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) { + // TODO(jonahwilliams): support texture coordinates in vertices + // https://github.com/flutter/flutter/issues/109956 + return {}; +} + +GeometryVertexType DLVerticesGeometry::GetVertexType() const { + auto* dl_colors = vertices_->colors(); + if (dl_colors != nullptr) { + return GeometryVertexType::kColor; + } + return GeometryVertexType::kPosition; +} + +std::optional DLVerticesGeometry::GetCoverage( + const Matrix& transform) const { + return ToRect(vertices_->bounds()); +} + +} // namespace impeller diff --git a/impeller/display_list/display_list_vertices_geometry.h b/impeller/display_list/display_list_vertices_geometry.h new file mode 100644 index 0000000000000..510f496a30110 --- /dev/null +++ b/impeller/display_list/display_list_vertices_geometry.h @@ -0,0 +1,61 @@ +// 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. + +#pragma once + +#include +#include + +#include "flutter/display_list/display_list_vertices.h" + +#include "impeller/entity/geometry.h" +#include "impeller/geometry/color.h" +#include "impeller/geometry/point.h" +#include "impeller/geometry/rect.h" + +namespace impeller { + +/// @brief A geometry that is created from a vertices object. +class DLVerticesGeometry : public VerticesGeometry { + public: + explicit DLVerticesGeometry(const flutter::DlVertices* vertices); + + ~DLVerticesGeometry(); + + static std::unique_ptr MakeVertices( + const flutter::DlVertices* vertices); + + // |VerticesGeometry| + GeometryResult GetPositionColorBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass, + Color paint_color, + BlendMode blend_mode) override; + + // |VerticesGeometry| + GeometryResult GetPositionUVBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) override; + + // |Geometry| + GeometryResult GetPositionBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) override; + + // |Geometry| + std::optional GetCoverage(const Matrix& transform) const override; + + // |Geometry| + GeometryVertexType GetVertexType() const override; + + private: + void NormalizeIndices(); + + const flutter::DlVertices* vertices_; + std::vector normalized_indices_; + + FML_DISALLOW_COPY_AND_ASSIGN(DLVerticesGeometry); +}; + +} // namespace impeller diff --git a/impeller/display_list/vertices_converter.cc b/impeller/display_list/vertices_converter.cc deleted file mode 100644 index 3bcb5e9f1cd52..0000000000000 --- a/impeller/display_list/vertices_converter.cc +++ /dev/null @@ -1,122 +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/display_list/vertices_converter.h" -#include "flutter/display_list/display_list_vertices.h" -#include "impeller/entity/entity.h" -#include "impeller/geometry/point.h" - -namespace impeller { - -static Rect ToRect(const SkRect& rect) { - return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); -} - -static std::vector fromColors(const flutter::DlVertices* vertices) { - std::vector colors; - auto* dl_colors = vertices->colors(); - if (dl_colors == nullptr) { - return colors; - } - auto color_count = vertices->vertex_count(); - colors.reserve(color_count); - for (int i = 0; i < color_count; i++) { - auto dl_color = dl_colors[i]; - colors.push_back({ - dl_color.getRedF(), - dl_color.getGreenF(), - dl_color.getBlueF(), - dl_color.getAlphaF(), - }); - } - return colors; -} - -static std::vector fromPoints(const flutter::DlVertices* vertices) { - std::vector points; - auto vertex_count = vertices->vertex_count(); - auto* dl_vertices = vertices->vertices(); - points.reserve(vertex_count); - for (int i = 0; i < vertex_count; i++) { - auto point = dl_vertices[i]; - points.push_back(Point(point.x(), point.y())); - } - return points; -} - -// Fan mode isn't natively supported. Unroll into triangle mode by -// manipulating the index array. -// -// In Triangle fan, the first vertex is shared across all triangles, and then -// each sliding window of two vertices plus that first vertex defines a -// triangle. -static std::vector fromFanIndices( - const flutter::DlVertices* vertices) { - FML_DCHECK(vertices->vertex_count() >= 3); - FML_DCHECK(vertices->mode() == flutter::DlVertexMode::kTriangleFan); - - std::vector indices; - - // Un-fan index buffer if provided. - if (vertices->index_count() > 0) { - auto* dl_indices = vertices->indices(); - auto center_point = dl_indices[0]; - for (int i = 1; i < vertices->index_count() - 1; i++) { - indices.push_back(center_point); - indices.push_back(dl_indices[i]); - indices.push_back(dl_indices[i + 1]); - } - } else { - // If indices were not provided, create an index buffer that unfans - // triangles instead of re-writing points, colors, et cetera. - for (int i = 1; i < vertices->vertex_count() - 1; i++) { - indices.push_back(0); - indices.push_back(i); - indices.push_back(i + 1); - } - } - return indices; -} - -static std::vector fromIndices(const flutter::DlVertices* vertices) { - if (vertices->mode() == flutter::DlVertexMode::kTriangleFan) { - return fromFanIndices(vertices); - } - - std::vector indices; - auto index_count = vertices->index_count(); - auto* dl_indices = vertices->indices(); - indices.reserve(index_count); - for (int i = 0; i < index_count; i++) { - auto index = dl_indices[i]; - indices.push_back(index); - } - return indices; -} - -Vertices ToVertices(const flutter::DlVertices* vertices) { - std::vector indices = fromIndices(vertices); - std::vector points = fromPoints(vertices); - std::vector colors = fromColors(vertices); - - VertexMode mode; - switch (vertices->mode()) { - case flutter::DlVertexMode::kTriangles: - mode = VertexMode::kTriangle; - break; - case flutter::DlVertexMode::kTriangleStrip: - mode = VertexMode::kTriangleStrip; - break; - case flutter::DlVertexMode::kTriangleFan: - // Unrolled into triangle mode by fromIndices. - mode = VertexMode::kTriangle; - break; - } - - auto bounds = vertices->bounds(); - return Vertices(std::move(points), std::move(indices), std::move(colors), - mode, ToRect(bounds)); -} - -} // namespace impeller diff --git a/impeller/display_list/vertices_converter.h b/impeller/display_list/vertices_converter.h deleted file mode 100644 index 0b68fc514275a..0000000000000 --- a/impeller/display_list/vertices_converter.h +++ /dev/null @@ -1,16 +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. - -#pragma once - -#include "flutter/display_list/display_list.h" -#include "flutter/display_list/display_list_vertices.h" -#include "impeller/geometry/vertices.h" - -namespace impeller { - -/// Convert DlVertices into impeller Vertices. -Vertices ToVertices(const flutter::DlVertices* vertices); - -} // namespace impeller diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 1175f5daef889..ecba665e6617a 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -66,6 +66,20 @@ impeller_shaders("entity_shaders") { ] } +impeller_shaders("modern_entity_shaders") { + name = "modern" + + if (impeller_enable_opengles) { + gles_language_version = "460" + } + + shaders = [ + "shaders/linear_gradient_ssbo_fill.frag", + "shaders/radial_gradient_ssbo_fill.frag", + "shaders/sweep_gradient_ssbo_fill.frag", + ] +} + impeller_component("entity") { sources = [ "contents/atlas_contents.cc", @@ -146,6 +160,7 @@ impeller_component("entity") { public_deps = [ ":entity_shaders", + ":modern_entity_shaders", "../archivist", "../image", "../renderer", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index dbc6fec50527e..fa6c6782f40cb 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -157,6 +157,14 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); + if (context_->GetBackendFeatures().ssbo_support) { + linear_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + radial_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + sweep_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + } sweep_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); rrect_blur_pipelines_[{}] = @@ -303,4 +311,8 @@ std::shared_ptr ContentContext::GetContext() const { return context_; } +const BackendFeatures& ContentContext::GetBackendFeatures() const { + return context_->GetBackendFeatures(); +} + } // namespace impeller diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 07c875bfe5a74..661ac5a58a9d0 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -72,6 +72,10 @@ #include "impeller/typographer/glyph_atlas.h" +#include "impeller/entity/linear_gradient_ssbo_fill.frag.h" +#include "impeller/entity/radial_gradient_ssbo_fill.frag.h" +#include "impeller/entity/sweep_gradient_ssbo_fill.frag.h" + namespace impeller { using LinearGradientFillPipeline = @@ -82,6 +86,15 @@ using RadialGradientFillPipeline = RenderPipelineT; using SweepGradientFillPipeline = RenderPipelineT; +using LinearGradientSSBOFillPipeline = + RenderPipelineT; +using RadialGradientSSBOFillPipeline = + RenderPipelineT; +using SweepGradientSSBOFillPipeline = + RenderPipelineT; using BlendPipeline = RenderPipelineT; using RRectBlurPipeline = RenderPipelineT; @@ -210,6 +223,24 @@ class ContentContext { return GetPipeline(linear_gradient_fill_pipelines_, opts); } + std::shared_ptr> + GetLinearGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(linear_gradient_ssbo_fill_pipelines_, opts); + } + + std::shared_ptr> + GetRadialGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(radial_gradient_ssbo_fill_pipelines_, opts); + } + + std::shared_ptr> + GetSweepGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(sweep_gradient_ssbo_fill_pipelines_, opts); + } + std::shared_ptr> GetRadialGradientFillPipeline( ContentContextOptions opts) const { return GetPipeline(radial_gradient_fill_pipelines_, opts); @@ -391,6 +422,8 @@ class ContentContext { std::shared_ptr GetGlyphAtlasContext() const; + const BackendFeatures& GetBackendFeatures() const; + using SubpassCallback = std::function; @@ -416,6 +449,12 @@ class ContentContext { mutable Variants linear_gradient_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; + mutable Variants + linear_gradient_ssbo_fill_pipelines_; + mutable Variants + radial_gradient_ssbo_fill_pipelines_; + mutable Variants + sweep_gradient_ssbo_fill_pipelines_; mutable Variants rrect_blur_pipelines_; mutable Variants texture_blend_pipelines_; mutable Variants texture_pipelines_; diff --git a/impeller/entity/contents/gradient_generator.cc b/impeller/entity/contents/gradient_generator.cc index f5fd4c70343fb..6a53719a90594 100644 --- a/impeller/entity/contents/gradient_generator.cc +++ b/impeller/entity/contents/gradient_generator.cc @@ -8,7 +8,6 @@ #include "flutter/fml/logging.h" #include "impeller/entity/contents/content_context.h" -#include "impeller/geometry/gradient.h" #include "impeller/renderer/context.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/texture.h" @@ -16,10 +15,8 @@ namespace impeller { std::shared_ptr CreateGradientTexture( - const std::vector& colors, - const std::vector& stops, + const GradientData& gradient_data, const std::shared_ptr& context) { - auto gradient_data = CreateGradientBuffer(colors, stops); if (gradient_data.texture_size == 0) { FML_DLOG(ERROR) << "Invalid gradient data."; return nullptr; diff --git a/impeller/entity/contents/gradient_generator.h b/impeller/entity/contents/gradient_generator.h index 1110da56837ea..2074d2a3e0440 100644 --- a/impeller/entity/contents/gradient_generator.h +++ b/impeller/entity/contents/gradient_generator.h @@ -11,6 +11,7 @@ #include "flutter/fml/macros.h" #include "flutter/impeller/renderer/texture.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -20,11 +21,10 @@ class Context; /** * @brief Create a host visible texture that contains the gradient defined - * by the provided colors and stops. + * by the provided gradient data. */ std::shared_ptr CreateGradientTexture( - const std::vector& colors, - const std::vector& stops, + const GradientData& gradient_data, const std::shared_ptr& context); } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 3b7b927c3e62f..f19d9077abf3c 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -47,11 +47,21 @@ void LinearGradientContents::SetTileMode(Entity::TileMode tile_mode) { bool LinearGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); + } + return RenderTexture(renderer, entity, pass); +} + +bool LinearGradientContents::RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = LinearGradientFillPipeline::VertexShader; using FS = LinearGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } @@ -106,4 +116,58 @@ bool LinearGradientContents::Render(const ContentContext& renderer, return true; } +bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = LinearGradientSSBOFillPipeline::VertexShader; + using FS = LinearGradientSSBOFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.start_point = start_point_; + gradient_info.end_point = end_point_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "LinearGradientSSBOFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetLinearGradientSSBOFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} + } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h index fbc9ec15f545d..2a2fd1c6c6632 100644 --- a/impeller/entity/contents/linear_gradient_contents.h +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -13,6 +13,7 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -42,6 +43,14 @@ class LinearGradientContents final : public ColorSourceContents { void SetTileMode(Entity::TileMode tile_mode); private: + bool RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + Point start_point_; Point end_point_; std::vector colors_; diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index 920c6255e76d1..ab94c3bde9221 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -10,6 +10,7 @@ #include "impeller/entity/contents/gradient_generator.h" #include "impeller/entity/entity.h" #include "impeller/entity/geometry.h" +#include "impeller/geometry/gradient.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" @@ -47,11 +48,75 @@ const std::vector& RadialGradientContents::GetStops() const { bool RadialGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); + } + return RenderTexture(renderer, entity, pass); +} + +bool RadialGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = RadialGradientSSBOFillPipeline::VertexShader; + using FS = RadialGradientSSBOFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.center = center_; + gradient_info.radius = radius_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "RadialGradientSSBOFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetRadialGradientSSBOFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} + +bool RadialGradientContents::RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = RadialGradientFillPipeline::VertexShader; using FS = RadialGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } diff --git a/impeller/entity/contents/radial_gradient_contents.h b/impeller/entity/contents/radial_gradient_contents.h index af659e6b8292f..6cb611d1ee68a 100644 --- a/impeller/entity/contents/radial_gradient_contents.h +++ b/impeller/entity/contents/radial_gradient_contents.h @@ -12,6 +12,7 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -41,6 +42,13 @@ class RadialGradientContents final : public ColorSourceContents { void SetTileMode(Entity::TileMode tile_mode); private: + bool RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; Point center_; Scalar radius_; std::vector colors_; diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 9b104a7bae2b4..395acc543c0d3 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -9,6 +9,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/gradient_generator.h" #include "impeller/entity/entity.h" +#include "impeller/geometry/gradient.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" @@ -52,11 +53,76 @@ const std::vector& SweepGradientContents::GetStops() const { bool SweepGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); + } + return RenderTexture(renderer, entity, pass); +} + +bool SweepGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = SweepGradientSSBOFillPipeline::VertexShader; + using FS = SweepGradientSSBOFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.center = center_; + gradient_info.bias = bias_; + gradient_info.scale = scale_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "SweepGradientSSBOFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetSweepGradientSSBOFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} + +bool SweepGradientContents::RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = SweepGradientFillPipeline::VertexShader; using FS = SweepGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } diff --git a/impeller/entity/contents/sweep_gradient_contents.h b/impeller/entity/contents/sweep_gradient_contents.h index a25c2f090cb66..94c448cc22961 100644 --- a/impeller/entity/contents/sweep_gradient_contents.h +++ b/impeller/entity/contents/sweep_gradient_contents.h @@ -12,6 +12,7 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" #include "impeller/geometry/scalar.h" @@ -42,6 +43,14 @@ class SweepGradientContents final : public ColorSourceContents { const std::vector& GetStops() const; private: + bool RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + Point center_; Scalar bias_; Scalar scale_; diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index d2d1c0d9bcfc8..1d6727d30565d 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -80,6 +80,7 @@ static bool CommonRender( SamplerDescriptor sampler_desc; sampler_desc.min_filter = MinMagFilter::kLinear; sampler_desc.mag_filter = MinMagFilter::kLinear; + sampler_desc.mip_filter = MipFilter::kNone; typename FS::FragInfo frag_info; frag_info.text_color = ToVector(color.Premultiply()); @@ -103,9 +104,9 @@ static bool CommonRender( // interpolated vertex information is also used in the fragment shader to // sample from the glyph atlas. - const std::vector unit_vertex_points = { - {0, 0}, {1, 0}, {0, 1}, {1, 1}}; - const std::vector indices = {0, 1, 2, 1, 2, 3}; + const std::array unit_points = {Point{0, 0}, Point{1, 0}, + Point{0, 1}, Point{1, 1}}; + const std::array indices = {0, 1, 2, 1, 2, 3}; VertexBufferBuilder vertex_builder; @@ -127,7 +128,7 @@ static bool CommonRender( for (const auto& run : frame.GetRuns()) { auto font = run.GetFont(); - auto glyph_size_ = ISize::Ceil(font.GetMetrics().GetBoundingBox().size); + auto glyph_size_ = font.GetMetrics().GetBoundingBox().size; auto glyph_size = Point{static_cast(glyph_size_.width), static_cast(glyph_size_.height)}; auto metrics_offset = @@ -141,22 +142,20 @@ static bool CommonRender( return false; } - auto atlas_position = - atlas_glyph_pos->origin + Point{1 / atlas_glyph_pos->size.width, - 1 / atlas_glyph_pos->size.height}; + auto atlas_position = atlas_glyph_pos->origin; auto atlas_glyph_size = Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height}; auto offset_glyph_position = glyph_position.position + metrics_offset; - for (const auto& point : unit_vertex_points) { + for (const auto& point : unit_points) { typename VS::PerVertexData vtx; - vtx.unit_vertex = point; - vtx.glyph_position = offset_glyph_position; - vtx.glyph_size = glyph_size; - vtx.atlas_position = atlas_position; - vtx.atlas_glyph_size = atlas_glyph_size; + vtx.unit_position = point; + vtx.destination_position = offset_glyph_position + Point(0.5, 0.5); + vtx.destination_size = glyph_size - Point(1.0, 1.0); + vtx.source_position = atlas_position + Point(0.5, 0.5); + vtx.source_glyph_size = atlas_glyph_size - Point(1.0, 1.0); if constexpr (std::is_same_v) { - vtx.color_glyph = + vtx.has_color = glyph_position.glyph.type == Glyph::Type::kBitmap ? 1.0 : 0.0; } vertex_builder.AppendVertex(std::move(vtx)); diff --git a/impeller/entity/contents/vertices_contents.h b/impeller/entity/contents/vertices_contents.h index b509b0a3b39fe..0f754c4c8ea25 100644 --- a/impeller/entity/contents/vertices_contents.h +++ b/impeller/entity/contents/vertices_contents.h @@ -15,7 +15,6 @@ #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" -#include "impeller/geometry/vertices.h" #include "impeller/renderer/sampler_descriptor.h" namespace impeller { diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 83ad0b47e4dab..ed89d7f9c9254 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -1203,77 +1203,6 @@ TEST_P(EntityTest, BorderMaskBlurCoverageIsCorrect) { } } -TEST_P(EntityTest, DrawVerticesSolidColorTrianglesWithoutIndices) { - std::vector positions = {Point(100, 300), Point(200, 100), - Point(300, 300)}; - std::vector colors = {Color::White(), Color::Green(), Color::White()}; - - Vertices vertices = Vertices(positions, {} /* indices */, colors, - VertexMode::kTriangle, Rect(100, 100, 300, 300)); - - std::shared_ptr contents = - std::make_shared(); - contents->SetGeometry(Geometry::MakeVertices(vertices)); - contents->SetBlendMode(BlendMode::kSourceOver); - contents->SetColor(Color::Red().WithAlpha(0.5)); - - Entity e; - e.SetTransformation(Matrix::MakeScale(GetContentScale())); - e.SetContents(contents); - - ASSERT_TRUE(OpenPlaygroundHere(e)); -} - -TEST_P(EntityTest, DrawVerticesLinearGradientWithoutIndices) { - std::vector positions = {Point(100, 300), Point(200, 100), - Point(300, 300)}; - - Vertices vertices = Vertices(positions, {} /* indices */, {} /* colors */, - VertexMode::kTriangle, Rect(100, 100, 300, 300)); - - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector stops = {0.0, 1.0}; - Matrix matrix = { - 1, 0, 0, 0, // - 0, 1, 0, 0, // - 0, 0, 1, 0, // - 0, 0, 0, 1 // - }; - auto contents = std::make_shared(); - contents->SetEndPoints({100, 100}, {300, 300}); - contents->SetColors(std::move(colors)); - contents->SetStops(std::move(stops)); - contents->SetTileMode(Entity::TileMode::kRepeat); - contents->SetMatrix(matrix); - contents->SetGeometry(Geometry::MakeVertices(vertices)); - - Entity e; - e.SetTransformation(Matrix::MakeScale(GetContentScale())); - e.SetContents(contents); - - ASSERT_TRUE(OpenPlaygroundHere(e)); -} - -TEST_P(EntityTest, DrawVerticesSolidColorTrianglesWithIndices) { - std::vector positions = {Point(100, 300), Point(200, 100), - Point(300, 300), Point(200, 500)}; - std::vector indices = {0, 1, 2, 0, 2, 3}; - - Vertices vertices = Vertices(positions, indices, {} /* colors */, - VertexMode::kTriangle, Rect(100, 100, 300, 300)); - - std::shared_ptr contents = - std::make_shared(); - contents->SetGeometry(Geometry::MakeVertices(vertices)); - contents->SetColor(Color::White()); - Entity e; - e.SetTransformation(Matrix::MakeScale(GetContentScale())); - e.SetContents(contents); - - ASSERT_TRUE(OpenPlaygroundHere(e)); -} - TEST_P(EntityTest, DrawAtlasNoColor) { // Draws the image as four squares stiched together. auto atlas = CreateTextureForFixture("bay_bridge.jpg"); diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 7c465480bf333..8bc37b352a978 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -18,11 +18,6 @@ Geometry::Geometry() = default; Geometry::~Geometry() = default; // static -std::unique_ptr Geometry::MakeVertices( - const Vertices& vertices) { - return std::make_unique(vertices); -} - std::unique_ptr Geometry::MakeFillPath(const Path& path) { return std::make_unique(path); } @@ -48,156 +43,6 @@ std::unique_ptr Geometry::MakeRect(Rect rect) { return std::make_unique(rect); } -/////// Vertices Geometry /////// - -VerticesGeometry::VerticesGeometry(const Vertices& vertices) - : vertices_(vertices) {} - -VerticesGeometry::~VerticesGeometry() = default; - -static PrimitiveType GetPrimitiveType(const Vertices& vertices) { - switch (vertices.GetMode()) { - case VertexMode::kTriangle: - return PrimitiveType::kTriangle; - case VertexMode::kTriangleStrip: - return PrimitiveType::kTriangleStrip; - } -} - -GeometryResult VerticesGeometry::GetPositionBuffer( - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) { - if (!vertices_.IsValid()) { - return {}; - } - - auto vertex_count = vertices_.GetPositions().size(); - size_t total_vtx_bytes = vertex_count * sizeof(float) * 2; - size_t total_idx_bytes = vertices_.GetIndices().size() * sizeof(uint16_t); - - DeviceBufferDescriptor buffer_desc; - buffer_desc.size = total_vtx_bytes + total_idx_bytes; - buffer_desc.storage_mode = StorageMode::kHostVisible; - - auto buffer = - renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc); - - const auto& positions = vertices_.GetPositions(); - if (!buffer->CopyHostBuffer( - reinterpret_cast(positions.data()), - Range{0, total_vtx_bytes}, 0)) { - return {}; - } - if (!buffer->CopyHostBuffer(reinterpret_cast(const_cast( - vertices_.GetIndices().data())), - Range{0, total_idx_bytes}, total_vtx_bytes)) { - return {}; - } - - return GeometryResult{ - .type = GetPrimitiveType(vertices_), - .vertex_buffer = - { - .vertex_buffer = {.buffer = buffer, - .range = Range{0, total_vtx_bytes}}, - .index_buffer = {.buffer = buffer, - .range = - Range{total_vtx_bytes, total_idx_bytes}}, - .index_count = vertices_.GetIndices().size(), - .index_type = IndexType::k16bit, - }, - .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(), - .prevent_overdraw = false, - }; -} - -GeometryResult VerticesGeometry::GetPositionColorBuffer( - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - Color paint_color, - BlendMode blend_mode) { - using VS = GeometryColorPipeline::VertexShader; - - if (!vertices_.IsValid()) { - return {}; - } - - auto vertex_count = vertices_.GetPositions().size(); - std::vector vertex_data(vertex_count); - { - const auto& positions = vertices_.GetPositions(); - const auto& colors = vertices_.GetColors(); - for (size_t i = 0; i < vertex_count; i++) { - auto color = Color::BlendColor(paint_color, colors[i], blend_mode); - vertex_data[i] = { - .position = positions[i], - .color = color, - }; - } - } - - size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData); - size_t total_idx_bytes = vertices_.GetIndices().size() * sizeof(uint16_t); - - DeviceBufferDescriptor buffer_desc; - buffer_desc.size = total_vtx_bytes + total_idx_bytes; - buffer_desc.storage_mode = StorageMode::kHostVisible; - - auto buffer = - renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc); - - if (!buffer->CopyHostBuffer(reinterpret_cast(vertex_data.data()), - Range{0, total_vtx_bytes}, 0)) { - return {}; - } - if (!buffer->CopyHostBuffer(reinterpret_cast(const_cast( - vertices_.GetIndices().data())), - Range{0, total_idx_bytes}, total_vtx_bytes)) { - return {}; - } - - return GeometryResult{ - .type = GetPrimitiveType(vertices_), - .vertex_buffer = - { - .vertex_buffer = {.buffer = buffer, - .range = Range{0, total_vtx_bytes}}, - .index_buffer = {.buffer = buffer, - .range = - Range{total_vtx_bytes, total_idx_bytes}}, - .index_count = vertices_.GetIndices().size(), - .index_type = IndexType::k16bit, - }, - .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(), - .prevent_overdraw = false, - }; -} - -GeometryResult VerticesGeometry::GetPositionUVBuffer( - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) { - // TODO(jonahwilliams): support texture coordinates in vertices - // https://github.com/flutter/flutter/issues/109956 - return {}; -} - -GeometryVertexType VerticesGeometry::GetVertexType() const { - if (vertices_.GetColors().size()) { - return GeometryVertexType::kColor; - } - return GeometryVertexType::kPosition; -} - -std::optional VerticesGeometry::GetCoverage( - const Matrix& transform) const { - return vertices_.GetTransformedBoundingBox(transform); -} - /////// Path Geometry /////// FillPathGeometry::FillPathGeometry(const Path& path) : path_(path) {} diff --git a/impeller/entity/geometry.h b/impeller/entity/geometry.h index 99780f2d8ce79..dabab1d1dc42a 100644 --- a/impeller/entity/geometry.h +++ b/impeller/entity/geometry.h @@ -9,7 +9,6 @@ #include "impeller/entity/solid_fill.vert.h" #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" -#include "impeller/geometry/vertices.h" #include "impeller/renderer/allocator.h" #include "impeller/renderer/host_buffer.h" #include "impeller/renderer/vertex_buffer.h" @@ -43,17 +42,12 @@ enum class Join { kBevel, }; -class VerticesGeometry; - class Geometry { public: Geometry(); virtual ~Geometry(); - static std::unique_ptr MakeVertices( - const Vertices& vertices); - static std::unique_ptr MakeFillPath(const Path& path); static std::unique_ptr MakeStrokePath( @@ -79,35 +73,15 @@ class Geometry { /// @brief A geometry that is created from a vertices object. class VerticesGeometry : public Geometry { public: - explicit VerticesGeometry(const Vertices& vertices); - - ~VerticesGeometry(); - - GeometryResult GetPositionColorBuffer(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - Color paint_color, - BlendMode blend_mode); - - GeometryResult GetPositionUVBuffer(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass); - - // |Geometry| - GeometryResult GetPositionBuffer(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) override; - - // |Geometry| - std::optional GetCoverage(const Matrix& transform) const override; - - // |Geometry| - GeometryVertexType GetVertexType() const override; - - private: - Vertices vertices_; - - FML_DISALLOW_COPY_AND_ASSIGN(VerticesGeometry); + virtual GeometryResult GetPositionColorBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass, + Color paint_color, + BlendMode blend_mode) = 0; + + virtual GeometryResult GetPositionUVBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) = 0; }; /// @brief A geometry that is created from a filled path object. diff --git a/impeller/entity/shaders/atlas_fill.frag b/impeller/entity/shaders/atlas_fill.frag index e211971ca1bb9..4862343926a78 100644 --- a/impeller/entity/shaders/atlas_fill.frag +++ b/impeller/entity/shaders/atlas_fill.frag @@ -3,6 +3,7 @@ // found in the LICENSE file. #include +#include uniform sampler2D texture_sampler; diff --git a/impeller/entity/shaders/atlas_fill.vert b/impeller/entity/shaders/atlas_fill.vert index 29d3c0a5be6e7..6140ad98788a4 100644 --- a/impeller/entity/shaders/atlas_fill.vert +++ b/impeller/entity/shaders/atlas_fill.vert @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform VertInfo { mat4 mvp; } diff --git a/impeller/entity/shaders/blending/advanced_blend.glsl b/impeller/entity/shaders/blending/advanced_blend.glsl index 6ff1d93ab6810..4fd47b059c0c8 100644 --- a/impeller/entity/shaders/blending/advanced_blend.glsl +++ b/impeller/entity/shaders/blending/advanced_blend.glsl @@ -5,6 +5,7 @@ #include #include #include +#include uniform BlendInfo { float dst_input_alpha; @@ -12,7 +13,8 @@ uniform BlendInfo { float src_y_coord_scale; float color_factor; vec4 color; // This color input is expected to be unpremultiplied. -} blend_info; +} +blend_info; uniform sampler2D texture_sampler_dst; uniform sampler2D texture_sampler_src; @@ -28,7 +30,8 @@ void main() { v_dst_texture_coords, // texture coordinates blend_info.dst_y_coord_scale, // y coordinate scale kTileModeDecal // tile mode - ) * blend_info.dst_input_alpha; + ) * + blend_info.dst_input_alpha; vec4 dst = IPUnpremultiply(dst_sample); vec4 src = blend_info.color_factor > 0 @@ -43,5 +46,5 @@ void main() { vec4 blended = vec4(Blend(dst.rgb, src.rgb), 1) * dst.a; frag_color = mix(dst_sample, blended, src.a); - //frag_color = dst_sample; + // frag_color = dst_sample; } diff --git a/impeller/entity/shaders/blending/advanced_blend.vert b/impeller/entity/shaders/blending/advanced_blend.vert index 715dd3dead9fe..cc72aeae97796 100644 --- a/impeller/entity/shaders/blending/advanced_blend.vert +++ b/impeller/entity/shaders/blending/advanced_blend.vert @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; } diff --git a/impeller/entity/shaders/blending/blend.frag b/impeller/entity/shaders/blending/blend.frag index c3f89be765349..af401a151d98d 100644 --- a/impeller/entity/shaders/blending/blend.frag +++ b/impeller/entity/shaders/blending/blend.frag @@ -3,13 +3,15 @@ // found in the LICENSE file. #include +#include uniform sampler2D texture_sampler_src; uniform FragInfo { float texture_sampler_y_coord_scale; float input_alpha; -} frag_info; +} +frag_info; in vec2 v_texture_coords; @@ -18,5 +20,5 @@ out vec4 frag_color; void main() { frag_color = IPSample(texture_sampler_src, v_texture_coords, frag_info.texture_sampler_y_coord_scale) * - frag_info.input_alpha; + frag_info.input_alpha; } diff --git a/impeller/entity/shaders/blending/blend.vert b/impeller/entity/shaders/blending/blend.vert index daa30f5650a3f..3b4a4bd430445 100644 --- a/impeller/entity/shaders/blending/blend.vert +++ b/impeller/entity/shaders/blending/blend.vert @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; in vec2 vertices; in vec2 texture_coords; diff --git a/impeller/entity/shaders/border_mask_blur.frag b/impeller/entity/shaders/border_mask_blur.frag index e9b56fa3cfe0a..a7652e5623967 100644 --- a/impeller/entity/shaders/border_mask_blur.frag +++ b/impeller/entity/shaders/border_mask_blur.frag @@ -4,6 +4,7 @@ #include #include +#include // Constant time mask blur for image borders. // @@ -18,7 +19,8 @@ uniform sampler2D texture_sampler; uniform FragInfo { float texture_sampler_y_coord_scale; -} frag_info; +} +frag_info; in vec2 v_texture_coords; in vec2 v_sigma_uv; diff --git a/impeller/entity/shaders/border_mask_blur.vert b/impeller/entity/shaders/border_mask_blur.vert index 3851a60aeb7fe..47a4d03e5978e 100644 --- a/impeller/entity/shaders/border_mask_blur.vert +++ b/impeller/entity/shaders/border_mask_blur.vert @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; diff --git a/impeller/entity/shaders/color_matrix_color_filter.frag b/impeller/entity/shaders/color_matrix_color_filter.frag index 43aa4c8c93976..e169f476b788e 100644 --- a/impeller/entity/shaders/color_matrix_color_filter.frag +++ b/impeller/entity/shaders/color_matrix_color_filter.frag @@ -4,10 +4,12 @@ #include #include +#include // A color filter that transforms colors through a 4x5 color matrix. // -// This filter can be used to change the saturation of pixels, convert from YUV to RGB, etc. +// This filter can be used to change the saturation of pixels, convert from YUV +// to RGB, etc. // // 4x5 matrix for transforming the color and alpha components of a Bitmap. // The matrix can be passed as single array, and is treated as follows: @@ -24,14 +26,16 @@ // B’ = k*R + l*G + m*B + n*A + o; // A’ = p*R + q*G + r*B + s*A + t; // -// That resulting color [R’, G’, B’, A’] then has each channel clamped to the 0 to 255 range. +// That resulting color [R’, G’, B’, A’] then has each channel clamped to the 0 +// to 255 range. uniform FragInfo { mat4 color_m; vec4 color_v; float texture_sampler_y_coord_scale; float input_alpha; -} frag_info; +} +frag_info; uniform sampler2D input_texture; @@ -41,14 +45,13 @@ out vec4 frag_color; void main() { vec4 input_color = IPSample(input_texture, v_position, frag_info.texture_sampler_y_coord_scale) * - frag_info.input_alpha; - + frag_info.input_alpha; // unpremultiply first, as filter inputs are premultiplied. vec4 color = IPUnpremultiply(input_color); color = clamp(frag_info.color_m * color + frag_info.color_v, 0.0, 1.0); - + // premultiply the outputs frag_color = vec4(color.rgb * color.a, color.a); } diff --git a/impeller/entity/shaders/color_matrix_color_filter.vert b/impeller/entity/shaders/color_matrix_color_filter.vert index b741b2744ec60..27b8ecedbf216 100644 --- a/impeller/entity/shaders/color_matrix_color_filter.vert +++ b/impeller/entity/shaders/color_matrix_color_filter.vert @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; in vec2 position; out vec2 v_position; diff --git a/impeller/entity/shaders/gaussian_blur.frag b/impeller/entity/shaders/gaussian_blur.frag index 06bd0f389ff47..b831baa6f8c77 100644 --- a/impeller/entity/shaders/gaussian_blur.frag +++ b/impeller/entity/shaders/gaussian_blur.frag @@ -16,6 +16,7 @@ #include #include #include +#include uniform sampler2D texture_sampler; uniform sampler2D alpha_mask_sampler; diff --git a/impeller/entity/shaders/gaussian_blur.vert b/impeller/entity/shaders/gaussian_blur.vert index 0fd3595a2d267..1fac06eb058b8 100644 --- a/impeller/entity/shaders/gaussian_blur.vert +++ b/impeller/entity/shaders/gaussian_blur.vert @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; } diff --git a/impeller/entity/shaders/glyph_atlas.frag b/impeller/entity/shaders/glyph_atlas.frag index 6fa09ad2dde2f..007748704f1d7 100644 --- a/impeller/entity/shaders/glyph_atlas.frag +++ b/impeller/entity/shaders/glyph_atlas.frag @@ -2,32 +2,32 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform sampler2D glyph_atlas_sampler; uniform FragInfo { vec2 atlas_size; vec4 text_color; -} frag_info; +} +frag_info; -in vec2 v_unit_vertex; -in vec2 v_atlas_position; -in vec2 v_atlas_glyph_size; -in float v_color_glyph; +in vec2 v_unit_position; +in vec2 v_source_position; +in vec2 v_source_glyph_size; +in float v_has_color; out vec4 frag_color; void main() { - vec2 scale_perspective = v_atlas_glyph_size / frag_info.atlas_size; - vec2 offset = v_atlas_position / frag_info.atlas_size; - if (v_color_glyph == 1.0) { - frag_color = texture( - glyph_atlas_sampler, - v_unit_vertex * scale_perspective + offset - ); + vec2 uv_size = v_source_glyph_size / frag_info.atlas_size; + vec2 offset = v_source_position / frag_info.atlas_size; + if (v_has_color == 1.0) { + frag_color = + texture(glyph_atlas_sampler, v_unit_position * uv_size + offset); } else { - frag_color = texture( - glyph_atlas_sampler, - v_unit_vertex * scale_perspective + offset - ).aaaa * frag_info.text_color; + frag_color = + texture(glyph_atlas_sampler, v_unit_position * uv_size + offset).aaaa * + frag_info.text_color; } } diff --git a/impeller/entity/shaders/glyph_atlas.vert b/impeller/entity/shaders/glyph_atlas.vert index e332d67d3be7f..bd527655c8984 100644 --- a/impeller/entity/shaders/glyph_atlas.vert +++ b/impeller/entity/shaders/glyph_atlas.vert @@ -3,27 +3,30 @@ // found in the LICENSE file. #include +#include uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; -in vec2 unit_vertex; -in vec2 glyph_position; -in vec2 glyph_size; -in vec2 atlas_position; -in vec2 atlas_glyph_size; -in float color_glyph; +in vec2 unit_position; +in vec2 destination_position; +in vec2 destination_size; +in vec2 source_position; +in vec2 source_glyph_size; +in float has_color; -out vec2 v_unit_vertex; -out vec2 v_atlas_position; -out vec2 v_atlas_glyph_size; -out float v_color_glyph; +out vec2 v_unit_position; +out vec2 v_source_position; +out vec2 v_source_glyph_size; +out float v_has_color; void main() { - gl_Position = IPPositionForGlyphPosition(frame_info.mvp, unit_vertex, glyph_position, glyph_size); - v_unit_vertex = unit_vertex; - v_atlas_position = atlas_position; - v_atlas_glyph_size = atlas_glyph_size; - v_color_glyph = color_glyph; + gl_Position = IPPositionForGlyphPosition( + frame_info.mvp, unit_position, destination_position, destination_size); + v_unit_position = unit_position; + v_source_position = source_position; + v_source_glyph_size = source_glyph_size; + v_has_color = has_color; } diff --git a/impeller/entity/shaders/glyph_atlas_sdf.frag b/impeller/entity/shaders/glyph_atlas_sdf.frag index 38518cee4247d..0ded6865c6371 100644 --- a/impeller/entity/shaders/glyph_atlas_sdf.frag +++ b/impeller/entity/shaders/glyph_atlas_sdf.frag @@ -2,33 +2,42 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform sampler2D glyph_atlas_sampler; uniform FragInfo { vec2 atlas_size; vec4 text_color; -} frag_info; +} +frag_info; -in vec2 v_unit_vertex; -in vec2 v_atlas_position; -in vec2 v_atlas_glyph_size; +in vec2 v_unit_position; +in vec2 v_source_position; +in vec2 v_source_glyph_size; out vec4 frag_color; void main() { - vec2 scale_perspective = v_atlas_glyph_size / frag_info.atlas_size; - vec2 offset = v_atlas_position / frag_info.atlas_size; + vec2 scale_perspective = v_source_glyph_size / frag_info.atlas_size; + vec2 offset = v_source_position / frag_info.atlas_size; // Inspired by Metal by Example's SDF text rendering shader: // https://github.com/metal-by-example/sample-code/blob/master/objc/12-TextRendering/TextRendering/Shaders.metal // Outline of glyph is the isocontour with value 50% float edge_distance = 0.5; - // Sample the signed-distance field to find distance from this fragment to the glyph outline - float sample_distance = texture(glyph_atlas_sampler, v_unit_vertex * scale_perspective + offset).a; - // Use local automatic gradients to find anti-aliased anisotropic edge width, cf. Gustavson 2012 + // Sample the signed-distance field to find distance from this fragment to the + // glyph outline + float sample_distance = + texture(glyph_atlas_sampler, v_unit_position * scale_perspective + offset) + .a; + // Use local automatic gradients to find anti-aliased anisotropic edge width, + // cf. Gustavson 2012 float edge_width = length(vec2(dFdx(sample_distance), dFdy(sample_distance))); - // Smooth the glyph edge by interpolating across the boundary in a band with the width determined above - float insideness = smoothstep(edge_distance - edge_width, edge_distance + edge_width, sample_distance); + // Smooth the glyph edge by interpolating across the boundary in a band with + // the width determined above + float insideness = smoothstep(edge_distance - edge_width, + edge_distance + edge_width, sample_distance); frag_color = frag_info.text_color * insideness; } diff --git a/impeller/entity/shaders/glyph_atlas_sdf.vert b/impeller/entity/shaders/glyph_atlas_sdf.vert index 830566304a123..4f6b62d059b5c 100644 --- a/impeller/entity/shaders/glyph_atlas_sdf.vert +++ b/impeller/entity/shaders/glyph_atlas_sdf.vert @@ -2,25 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + #include uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; -in vec2 unit_vertex; -in vec2 glyph_position; -in vec2 glyph_size; -in vec2 atlas_position; -in vec2 atlas_glyph_size; +in vec2 unit_position; +in vec2 destination_position; +in vec2 destination_size; +in vec2 source_position; +in vec2 source_glyph_size; -out vec2 v_unit_vertex; -out vec2 v_atlas_position; -out vec2 v_atlas_glyph_size; +out vec2 v_unit_position; +out vec2 v_source_position; +out vec2 v_source_glyph_size; void main() { - gl_Position = IPPositionForGlyphPosition(frame_info.mvp, unit_vertex, glyph_position, glyph_size); - v_unit_vertex = unit_vertex; - v_atlas_position = atlas_position; - v_atlas_glyph_size = atlas_glyph_size; + gl_Position = IPPositionForGlyphPosition( + frame_info.mvp, unit_position, destination_position, destination_size); + v_unit_position = unit_position; + v_source_position = source_position; + v_source_glyph_size = source_glyph_size; } diff --git a/impeller/entity/shaders/gradient_fill.vert b/impeller/entity/shaders/gradient_fill.vert index 4b793dbfa183d..824f496ea8c22 100644 --- a/impeller/entity/shaders/gradient_fill.vert +++ b/impeller/entity/shaders/gradient_fill.vert @@ -3,11 +3,13 @@ // found in the LICENSE file. #include +#include uniform FrameInfo { mat4 mvp; mat4 matrix; -} frame_info; +} +frame_info; in vec2 position; diff --git a/impeller/entity/shaders/linear_gradient_fill.frag b/impeller/entity/shaders/linear_gradient_fill.frag index 577dd7dbb4741..008d0a562e255 100644 --- a/impeller/entity/shaders/linear_gradient_fill.frag +++ b/impeller/entity/shaders/linear_gradient_fill.frag @@ -3,6 +3,7 @@ // found in the LICENSE file. #include +#include uniform sampler2D texture_sampler; @@ -13,7 +14,8 @@ uniform GradientInfo { float texture_sampler_y_coord_scale; float alpha; vec2 half_texel; -} gradient_info; +} +gradient_info; in vec2 v_position; @@ -21,16 +23,13 @@ out vec4 frag_color; void main() { float len = length(gradient_info.end_point - gradient_info.start_point); - float dot = dot( - v_position - gradient_info.start_point, - gradient_info.end_point - gradient_info.start_point - ); + float dot = dot(v_position - gradient_info.start_point, + gradient_info.end_point - gradient_info.start_point); float t = dot / (len * len); frag_color = IPSampleLinearWithTileMode( - texture_sampler, - vec2(t, 0.5), - gradient_info.texture_sampler_y_coord_scale, - gradient_info.half_texel, - gradient_info.tile_mode); - frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; + texture_sampler, vec2(t, 0.5), + gradient_info.texture_sampler_y_coord_scale, gradient_info.half_texel, + gradient_info.tile_mode); + frag_color = + vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; } diff --git a/impeller/entity/shaders/linear_gradient_ssbo_fill.frag b/impeller/entity/shaders/linear_gradient_ssbo_fill.frag new file mode 100644 index 0000000000000..a2443ece8cadf --- /dev/null +++ b/impeller/entity/shaders/linear_gradient_ssbo_fill.frag @@ -0,0 +1,44 @@ +// 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 +#include + +readonly buffer ColorData { + vec4 colors[]; +} +color_data; + +uniform GradientInfo { + vec2 start_point; + vec2 end_point; + float alpha; + float tile_mode; + float colors_length; +} +gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + float len = length(gradient_info.end_point - gradient_info.start_point); + float dot = dot(v_position - gradient_info.start_point, + gradient_info.end_point - gradient_info.start_point); + float t = dot / (len * len); + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], + color_data.colors[int(values.y)], values.z); + frag_color = + vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; +} diff --git a/impeller/entity/shaders/linear_to_srgb_filter.frag b/impeller/entity/shaders/linear_to_srgb_filter.frag index e4fb50b1a2ead..0d6a99263df77 100644 --- a/impeller/entity/shaders/linear_to_srgb_filter.frag +++ b/impeller/entity/shaders/linear_to_srgb_filter.frag @@ -4,6 +4,7 @@ #include #include +#include // A color filter that applies the sRGB gamma curve to the color. // @@ -14,7 +15,8 @@ uniform sampler2D input_texture; uniform FragInfo { float texture_sampler_y_coord_scale; float input_alpha; -} frag_info; +} +frag_info; in vec2 v_position; out vec4 frag_color; @@ -22,7 +24,7 @@ out vec4 frag_color; void main() { vec4 input_color = IPSample(input_texture, v_position, frag_info.texture_sampler_y_coord_scale) * - frag_info.input_alpha; + frag_info.input_alpha; vec4 color = IPUnpremultiply(input_color); for (int i = 0; i < 3; i++) { diff --git a/impeller/entity/shaders/linear_to_srgb_filter.vert b/impeller/entity/shaders/linear_to_srgb_filter.vert index b741b2744ec60..27b8ecedbf216 100644 --- a/impeller/entity/shaders/linear_to_srgb_filter.vert +++ b/impeller/entity/shaders/linear_to_srgb_filter.vert @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; in vec2 position; out vec2 v_position; diff --git a/impeller/entity/shaders/morphology_filter.frag b/impeller/entity/shaders/morphology_filter.frag index 8d35ab13186a1..dc80727a80c92 100644 --- a/impeller/entity/shaders/morphology_filter.frag +++ b/impeller/entity/shaders/morphology_filter.frag @@ -4,12 +4,13 @@ #include #include +#include // These values must correspond to the order of the items in the // 'FilterContents::MorphType' enum class. const float kMorphTypeDilate = 0; const float kMorphTypeErode = 1; - + uniform sampler2D texture_sampler; uniform FragInfo { @@ -30,13 +31,12 @@ void main() { for (float i = -frag_info.radius; i <= frag_info.radius; i++) { vec2 texture_coords = v_texture_coords + uv_offset * i; vec4 color; - color = - IPSampleWithTileMode( - texture_sampler, // sampler - texture_coords, // texture coordinates - frag_info.texture_sampler_y_coord_scale, // y coordinate scale - kTileModeDecal // tile mode - ); + color = IPSampleWithTileMode( + texture_sampler, // sampler + texture_coords, // texture coordinates + frag_info.texture_sampler_y_coord_scale, // y coordinate scale + kTileModeDecal // tile mode + ); if (frag_info.morph_type == kMorphTypeDilate) { result = max(color, result); } else { diff --git a/impeller/entity/shaders/morphology_filter.vert b/impeller/entity/shaders/morphology_filter.vert index c76f3b8a57f48..a504e7a9e23c8 100644 --- a/impeller/entity/shaders/morphology_filter.vert +++ b/impeller/entity/shaders/morphology_filter.vert @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; } diff --git a/impeller/entity/shaders/position.vert b/impeller/entity/shaders/position.vert index 949fe02afd3f7..048062f0033f5 100644 --- a/impeller/entity/shaders/position.vert +++ b/impeller/entity/shaders/position.vert @@ -3,11 +3,13 @@ // found in the LICENSE file. #include +#include uniform VertInfo { mat4 mvp; vec4 color; -} vert_info; +} +vert_info; in vec2 position; diff --git a/impeller/entity/shaders/position_color.vert b/impeller/entity/shaders/position_color.vert index fe62e61474b7b..f36ded01e0257 100644 --- a/impeller/entity/shaders/position_color.vert +++ b/impeller/entity/shaders/position_color.vert @@ -3,10 +3,12 @@ // found in the LICENSE file. #include +#include uniform VertInfo { mat4 mvp; -} vert_info; +} +vert_info; in vec2 position; in vec4 color; diff --git a/impeller/entity/shaders/position_uv.vert b/impeller/entity/shaders/position_uv.vert index cb8850b795173..e49949a801277 100644 --- a/impeller/entity/shaders/position_uv.vert +++ b/impeller/entity/shaders/position_uv.vert @@ -3,10 +3,12 @@ // found in the LICENSE file. #include +#include uniform VertInfo { mat4 mvp; -} vert_info; +} +vert_info; in vec2 position; in vec2 uv; diff --git a/impeller/entity/shaders/radial_gradient_fill.frag b/impeller/entity/shaders/radial_gradient_fill.frag index 31d3ae2463632..9d3a4d64bb7d1 100644 --- a/impeller/entity/shaders/radial_gradient_fill.frag +++ b/impeller/entity/shaders/radial_gradient_fill.frag @@ -3,6 +3,7 @@ // found in the LICENSE file. #include +#include uniform sampler2D texture_sampler; @@ -13,7 +14,8 @@ uniform GradientInfo { float texture_sampler_y_coord_scale; float alpha; vec2 half_texel; -} gradient_info; +} +gradient_info; in vec2 v_position; @@ -23,10 +25,9 @@ void main() { float len = length(v_position - gradient_info.center); float t = len / gradient_info.radius; frag_color = IPSampleLinearWithTileMode( - texture_sampler, - vec2(t, 0.5), - gradient_info.texture_sampler_y_coord_scale, - gradient_info.half_texel, - gradient_info.tile_mode); - frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; + texture_sampler, vec2(t, 0.5), + gradient_info.texture_sampler_y_coord_scale, gradient_info.half_texel, + gradient_info.tile_mode); + frag_color = + vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; } diff --git a/impeller/entity/shaders/radial_gradient_ssbo_fill.frag b/impeller/entity/shaders/radial_gradient_ssbo_fill.frag new file mode 100644 index 0000000000000..0b6496c0d7a68 --- /dev/null +++ b/impeller/entity/shaders/radial_gradient_ssbo_fill.frag @@ -0,0 +1,42 @@ +// 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 +#include + +readonly buffer ColorData { + vec4 colors[]; +} +color_data; + +uniform GradientInfo { + vec2 center; + float radius; + float tile_mode; + float alpha; + float colors_length; +} +gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + float len = length(v_position - gradient_info.center); + float t = len / gradient_info.radius; + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], + color_data.colors[int(values.y)], values.z); + frag_color = + vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; +} diff --git a/impeller/entity/shaders/rrect_blur.frag b/impeller/entity/shaders/rrect_blur.frag index bc400d0354e06..7a82a57805e63 100644 --- a/impeller/entity/shaders/rrect_blur.frag +++ b/impeller/entity/shaders/rrect_blur.frag @@ -3,6 +3,7 @@ // found in the LICENSE file. #include +#include uniform FragInfo { vec4 color; diff --git a/impeller/entity/shaders/rrect_blur.vert b/impeller/entity/shaders/rrect_blur.vert index 36711c6ede5e0..8ada4365f4138 100644 --- a/impeller/entity/shaders/rrect_blur.vert +++ b/impeller/entity/shaders/rrect_blur.vert @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform VertInfo { mat4 mvp; } diff --git a/impeller/entity/shaders/runtime_effect.vert b/impeller/entity/shaders/runtime_effect.vert index a29402d71e627..bf69bf1ed69a7 100644 --- a/impeller/entity/shaders/runtime_effect.vert +++ b/impeller/entity/shaders/runtime_effect.vert @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform VertInfo { mat4 mvp; -} vert_info; +} +vert_info; in vec2 position; out vec2 v_position; diff --git a/impeller/entity/shaders/solid_fill.frag b/impeller/entity/shaders/solid_fill.frag index 5d9c83604dd68..28c7776da9e1d 100644 --- a/impeller/entity/shaders/solid_fill.frag +++ b/impeller/entity/shaders/solid_fill.frag @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FragInfo { vec4 color; } diff --git a/impeller/entity/shaders/solid_fill.vert b/impeller/entity/shaders/solid_fill.vert index 8fdc5b1ea3f1e..3ced5986276c7 100644 --- a/impeller/entity/shaders/solid_fill.vert +++ b/impeller/entity/shaders/solid_fill.vert @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform VertInfo { mat4 mvp; } diff --git a/impeller/entity/shaders/srgb_to_linear_filter.frag b/impeller/entity/shaders/srgb_to_linear_filter.frag index 7c524fe80c291..fcef8e99d545d 100644 --- a/impeller/entity/shaders/srgb_to_linear_filter.frag +++ b/impeller/entity/shaders/srgb_to_linear_filter.frag @@ -8,12 +8,15 @@ // Creates a color filter that applies the inverse of the sRGB gamma curve // to the RGB channels. +#include + uniform sampler2D input_texture; uniform FragInfo { float texture_sampler_y_coord_scale; float input_alpha; -} frag_info; +} +frag_info; in vec2 v_position; out vec4 frag_color; @@ -21,7 +24,7 @@ out vec4 frag_color; void main() { vec4 input_color = IPSample(input_texture, v_position, frag_info.texture_sampler_y_coord_scale) * - frag_info.input_alpha; + frag_info.input_alpha; vec4 color = IPUnpremultiply(input_color); for (int i = 0; i < 3; i++) { diff --git a/impeller/entity/shaders/srgb_to_linear_filter.vert b/impeller/entity/shaders/srgb_to_linear_filter.vert index b741b2744ec60..27b8ecedbf216 100644 --- a/impeller/entity/shaders/srgb_to_linear_filter.vert +++ b/impeller/entity/shaders/srgb_to_linear_filter.vert @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; in vec2 position; out vec2 v_position; diff --git a/impeller/entity/shaders/sweep_gradient_fill.frag b/impeller/entity/shaders/sweep_gradient_fill.frag index 2fe042dd2c8c2..47d70f023a4c6 100644 --- a/impeller/entity/shaders/sweep_gradient_fill.frag +++ b/impeller/entity/shaders/sweep_gradient_fill.frag @@ -4,6 +4,7 @@ #include #include +#include uniform sampler2D texture_sampler; @@ -15,7 +16,8 @@ uniform GradientInfo { float texture_sampler_y_coord_scale; float alpha; vec2 half_texel; -} gradient_info; +} +gradient_info; in vec2 v_position; @@ -25,12 +27,12 @@ void main() { vec2 coord = v_position - gradient_info.center; float angle = atan(-coord.y, -coord.x); - float t = (angle * k1Over2Pi + 0.5 + gradient_info.bias) * gradient_info.scale; + float t = + (angle * k1Over2Pi + 0.5 + gradient_info.bias) * gradient_info.scale; frag_color = IPSampleLinearWithTileMode( - texture_sampler, - vec2(t, 0.5), - gradient_info.texture_sampler_y_coord_scale, - gradient_info.half_texel, - gradient_info.tile_mode); - frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; + texture_sampler, vec2(t, 0.5), + gradient_info.texture_sampler_y_coord_scale, gradient_info.half_texel, + gradient_info.tile_mode); + frag_color = + vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; } diff --git a/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag b/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag new file mode 100644 index 0000000000000..9fe30f94ad99c --- /dev/null +++ b/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag @@ -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. + +#include +#include +#include +#include + +readonly buffer ColorData { + vec4 colors[]; +} +color_data; + +uniform GradientInfo { + vec2 center; + float bias; + float scale; + float tile_mode; + float alpha; + float colors_length; +} +gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + vec2 coord = v_position - gradient_info.center; + float angle = atan(-coord.y, -coord.x); + float t = + (angle * k1Over2Pi + 0.5 + gradient_info.bias) * gradient_info.scale; + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], + color_data.colors[int(values.y)], values.z); + frag_color = + vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; +} diff --git a/impeller/entity/shaders/texture_fill.frag b/impeller/entity/shaders/texture_fill.frag index 913cc7e1e8a70..9b8a8a6bab802 100644 --- a/impeller/entity/shaders/texture_fill.frag +++ b/impeller/entity/shaders/texture_fill.frag @@ -3,6 +3,7 @@ // found in the LICENSE file. #include +#include uniform sampler2D texture_sampler; diff --git a/impeller/entity/shaders/texture_fill.vert b/impeller/entity/shaders/texture_fill.vert index c8abc9aaabbce..212f9e288f34f 100644 --- a/impeller/entity/shaders/texture_fill.vert +++ b/impeller/entity/shaders/texture_fill.vert @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform VertInfo { mat4 mvp; } diff --git a/impeller/entity/shaders/tiled_texture_fill.frag b/impeller/entity/shaders/tiled_texture_fill.frag index 9892643517043..2c3c4ea8ab07a 100644 --- a/impeller/entity/shaders/tiled_texture_fill.frag +++ b/impeller/entity/shaders/tiled_texture_fill.frag @@ -3,6 +3,7 @@ // found in the LICENSE file. #include +#include uniform sampler2D texture_sampler; @@ -26,5 +27,6 @@ void main() { frag_info.texture_sampler_y_coord_scale, // y coordinate scale frag_info.x_tile_mode, // x tile mode frag_info.y_tile_mode // y tile mode - ) * frag_info.alpha; + ) * + frag_info.alpha; } diff --git a/impeller/entity/shaders/tiled_texture_fill.vert b/impeller/entity/shaders/tiled_texture_fill.vert index db73769940067..dabcdf780bf54 100644 --- a/impeller/entity/shaders/tiled_texture_fill.vert +++ b/impeller/entity/shaders/tiled_texture_fill.vert @@ -3,6 +3,7 @@ // found in the LICENSE file. #include +#include uniform VertInfo { mat4 mvp; diff --git a/impeller/entity/shaders/vertices.frag b/impeller/entity/shaders/vertices.frag index ccad5b7d3e141..c42e809ecc14d 100644 --- a/impeller/entity/shaders/vertices.frag +++ b/impeller/entity/shaders/vertices.frag @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + in vec4 v_color; out vec4 frag_color; diff --git a/impeller/entity/shaders/yuv_to_rgb_filter.frag b/impeller/entity/shaders/yuv_to_rgb_filter.frag index b734b486024ab..d33e0d541bc08 100644 --- a/impeller/entity/shaders/yuv_to_rgb_filter.frag +++ b/impeller/entity/shaders/yuv_to_rgb_filter.frag @@ -4,6 +4,7 @@ #include #include +#include uniform sampler2D y_texture; uniform sampler2D uv_texture; @@ -17,7 +18,8 @@ uniform FragInfo { float texture_sampler_y_coord_scale; mat4 matrix; float yuv_color_space; -} frag_info; +} +frag_info; in vec2 v_position; out vec4 frag_color; @@ -29,7 +31,11 @@ void main() { yuv_offset.x = 16.0 / 255.0; } - yuv.x = IPSample(y_texture, v_position, frag_info.texture_sampler_y_coord_scale).r; - yuv.yz = IPSample(uv_texture, v_position, frag_info.texture_sampler_y_coord_scale).rg; + yuv.x = + IPSample(y_texture, v_position, frag_info.texture_sampler_y_coord_scale) + .r; + yuv.yz = + IPSample(uv_texture, v_position, frag_info.texture_sampler_y_coord_scale) + .rg; frag_color = frag_info.matrix * vec4(yuv - yuv_offset, 1); } diff --git a/impeller/entity/shaders/yuv_to_rgb_filter.vert b/impeller/entity/shaders/yuv_to_rgb_filter.vert index b741b2744ec60..27b8ecedbf216 100644 --- a/impeller/entity/shaders/yuv_to_rgb_filter.vert +++ b/impeller/entity/shaders/yuv_to_rgb_filter.vert @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; in vec2 position; out vec2 v_position; diff --git a/impeller/fixtures/box_fade.frag b/impeller/fixtures/box_fade.frag index 6e6b66bae1f0b..5acb1cba44f84 100644 --- a/impeller/fixtures/box_fade.frag +++ b/impeller/fixtures/box_fade.frag @@ -6,7 +6,8 @@ uniform FrameInfo { float current_time; vec2 cursor_position; vec2 window_size; -} frame_info; +} +frame_info; in vec2 interporlated_texture_coordinates; @@ -18,5 +19,7 @@ uniform sampler2D contents2; void main() { vec4 tex1 = texture(contents1, interporlated_texture_coordinates); vec4 tex2 = texture(contents2, interporlated_texture_coordinates); - frag_color = mix(tex1, tex2, clamp(frame_info.cursor_position.x / frame_info.window_size.x, 0.0, 1.0)); + frag_color = mix( + tex1, tex2, + clamp(frame_info.cursor_position.x / frame_info.window_size.x, 0.0, 1.0)); } diff --git a/impeller/fixtures/box_fade.vert b/impeller/fixtures/box_fade.vert index ac3674d80fbc7..05f52f3c70aff 100644 --- a/impeller/fixtures/box_fade.vert +++ b/impeller/fixtures/box_fade.vert @@ -4,7 +4,8 @@ uniform UniformBuffer { mat4 mvp; -} uniform_buffer; +} +uniform_buffer; in vec3 vertex_position; in vec2 texture_coordinates; diff --git a/impeller/fixtures/ink_sparkle.frag b/impeller/fixtures/ink_sparkle.frag index b8dea9bf0099f..6e2940cf1a402 100644 --- a/impeller/fixtures/ink_sparkle.frag +++ b/impeller/fixtures/ink_sparkle.frag @@ -31,7 +31,7 @@ layout(location = 0) out vec4 fragColor; const float PI = 3.1415926535897932384626; const float PI_ROTATE_RIGHT = PI * 0.0078125; const float PI_ROTATE_LEFT = PI * -0.0078125; -const float ONE_THIRD = 1./3.; +const float ONE_THIRD = 1. / 3.; const vec2 TURBULENCE_SCALE = vec2(0.8); float triangle_noise(highp vec2 n) { @@ -45,7 +45,7 @@ float threshold(float v, float l, float h) { return step(l, v) * (1.0 - step(h, v)); } -mat2 rotate2d(vec2 rad){ +mat2 rotate2d(vec2 rad) { return mat2(rad.x, -rad.y, rad.y, rad.x); } @@ -61,7 +61,11 @@ float soft_ring(vec2 uv, vec2 xy, float radius, float thickness, float blur) { return clamp(circle_outer - circle_inner, 0.0, 1.0); } -float circle_grid(vec2 resolution, vec2 p, vec2 xy, vec2 rotation, float cell_diameter) { +float circle_grid(vec2 resolution, + vec2 p, + vec2 xy, + vec2 rotation, + float cell_diameter) { p = rotate2d(rotation) * (xy - p) + xy; p = mod(p, cell_diameter) / resolution; float cell_uv = cell_diameter / resolution.y * 0.5; @@ -80,9 +84,12 @@ float sparkle(vec2 uv, float t) { float turbulence(vec2 uv) { vec2 uv_scale = uv * TURBULENCE_SCALE; - float g1 = circle_grid(TURBULENCE_SCALE, uv_scale, u_circle1, u_rotation1, 0.17); - float g2 = circle_grid(TURBULENCE_SCALE, uv_scale, u_circle2, u_rotation2, 0.2); - float g3 = circle_grid(TURBULENCE_SCALE, uv_scale, u_circle3, u_rotation3, 0.275); + float g1 = + circle_grid(TURBULENCE_SCALE, uv_scale, u_circle1, u_rotation1, 0.17); + float g2 = + circle_grid(TURBULENCE_SCALE, uv_scale, u_circle2, u_rotation2, 0.2); + float g3 = + circle_grid(TURBULENCE_SCALE, uv_scale, u_circle3, u_rotation3, 0.275); float v = (g1 * g1 + g2 - g3) * 0.5; return clamp(0.45 + 0.8 * v, 0.0, 1.0); } @@ -94,9 +101,12 @@ void main() { float radius = u_max_radius * u_radius_scale; float turbulence = turbulence(uv); float ring = soft_ring(p, u_center, radius, 0.05 * u_max_radius, u_blur); - float sparkle = sparkle(density_uv, u_noise_phase) * ring * turbulence * u_sparkle_alpha; - float wave_alpha = soft_circle(p, u_center, radius, u_blur) * u_alpha * u_color.a; + float sparkle = + sparkle(density_uv, u_noise_phase) * ring * turbulence * u_sparkle_alpha; + float wave_alpha = + soft_circle(p, u_center, radius, u_blur) * u_alpha * u_color.a; vec4 wave_color = vec4(u_color.rgb * wave_alpha, wave_alpha); - vec4 sparkle_color = vec4(u_sparkle_color.rgb * u_sparkle_color.a, u_sparkle_color.a); + vec4 sparkle_color = + vec4(u_sparkle_color.rgb * u_sparkle_color.a, u_sparkle_color.a); fragColor = mix(wave_color, sparkle_color, sparkle); } diff --git a/impeller/fixtures/instanced_draw.vert b/impeller/fixtures/instanced_draw.vert index 90890b198e575..9a674726cd900 100644 --- a/impeller/fixtures/instanced_draw.vert +++ b/impeller/fixtures/instanced_draw.vert @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - #ifdef IMPELLER_TARGET_OPENGLES void main() { @@ -13,22 +12,22 @@ void main() { uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; readonly buffer InstanceInfo { vec4 colors[]; -} instance_info; +} +instance_info; in vec2 vtx; out vec4 v_color; -void main () { - gl_Position = frame_info.mvp * - vec4(vtx.x + 105.0 * gl_InstanceIndex, - vtx.y + 105.0 * gl_InstanceIndex, - 0.0, - 1.0); +void main() { + gl_Position = + frame_info.mvp * vec4(vtx.x + 105.0 * gl_InstanceIndex, + vtx.y + 105.0 * gl_InstanceIndex, 0.0, 1.0); v_color = instance_info.colors[gl_InstanceIndex]; } diff --git a/impeller/fixtures/resources_limit.vert b/impeller/fixtures/resources_limit.vert index 95c84ee8bfc76..f3f9db8c3a504 100644 --- a/impeller/fixtures/resources_limit.vert +++ b/impeller/fixtures/resources_limit.vert @@ -3,7 +3,6 @@ // found in the LICENSE file. uniform sampler1D tex; -void main() -{ - vec4 x = textureOffset(tex, 1.0, -10); +void main() { + vec4 x = textureOffset(tex, 1.0, -10); } diff --git a/impeller/fixtures/runtime_stage_example.frag b/impeller/fixtures/runtime_stage_example.frag index 678cb95c263be..81ee6cd820518 100644 --- a/impeller/fixtures/runtime_stage_example.frag +++ b/impeller/fixtures/runtime_stage_example.frag @@ -8,8 +8,8 @@ layout(location = 1) uniform vec2 iResolution; layout(location = 0) out vec4 fragColor; void main() { - vec2 uv = gl_FragCoord.xy/iResolution; + vec2 uv = gl_FragCoord.xy / iResolution; float t = 4 * iTime; - vec3 col = 0.5 + 0.5*cos(t + uv.xyx + vec3(0,1,4)); - fragColor = vec4(col,1.0); + vec3 col = 0.5 + 0.5 * cos(t + uv.xyx + vec3(0, 1, 4)); + fragColor = vec4(col, 1.0); } diff --git a/impeller/fixtures/sa%m#ple.vert b/impeller/fixtures/sa%m#ple.vert index fc7e9d1122000..746824ec0adee 100644 --- a/impeller/fixtures/sa%m#ple.vert +++ b/impeller/fixtures/sa%m#ple.vert @@ -6,7 +6,8 @@ uniform UniformBufferObject { Uniforms uniforms; -} ubo; +} +ubo; uniform sampler2D world; @@ -18,6 +19,8 @@ in float stuff; out vec4 outStuff; void main() { - gl_Position = ubo.uniforms.projection * ubo.uniforms.view * ubo.uniforms.model * vec4(inPosition22, 1.0) * inAnotherPosition; + gl_Position = ubo.uniforms.projection * ubo.uniforms.view * + ubo.uniforms.model * vec4(inPosition22, 1.0) * + inAnotherPosition; outStuff = texture(world, inPosition); } diff --git a/impeller/fixtures/sample.comp b/impeller/fixtures/sample.comp index a0a0f1661a01e..c5dc05d743c22 100644 --- a/impeller/fixtures/sample.comp +++ b/impeller/fixtures/sample.comp @@ -8,26 +8,29 @@ struct SomeStruct { layout(binding = 0) writeonly buffer Output { vec4 elements[]; -} output_data; +} +output_data; layout(binding = 1) readonly buffer Input0 { int some_int; ivec2 fixed_array[3]; vec4 elements[]; -} input_data0; +} +input_data0; layout(binding = 2) readonly buffer Input1 { SomeStruct some_struct; uvec2 fixed_array[4]; vec4 elements[]; -} input_data1; +} +input_data1; uniform Info { uint count; -} info; +} +info; -void main() -{ +void main() { uint ident = gl_GlobalInvocationID.x; // TODO(dnfield): https://github.com/flutter/flutter/issues/112683 // We should be able to use length here instead of an extra arrgument. @@ -35,8 +38,12 @@ void main() return; } - output_data.elements[ident] = input_data0.elements[ident] * input_data1.elements[ident]; - output_data.elements[ident].x += input_data0.fixed_array[1].x + input_data1.some_struct.i; - output_data.elements[ident].y += input_data1.fixed_array[0].y + input_data1.some_struct.vf.x; - output_data.elements[ident].z += input_data0.some_int + input_data1.some_struct.vf.y; + output_data.elements[ident] = + input_data0.elements[ident] * input_data1.elements[ident]; + output_data.elements[ident].x += + input_data0.fixed_array[1].x + input_data1.some_struct.i; + output_data.elements[ident].y += + input_data1.fixed_array[0].y + input_data1.some_struct.vf.x; + output_data.elements[ident].z += + input_data0.some_int + input_data1.some_struct.vf.y; } diff --git a/impeller/fixtures/sample.tesc b/impeller/fixtures/sample.tesc index 6eb4156e21966..d6fe50408fe7a 100644 --- a/impeller/fixtures/sample.tesc +++ b/impeller/fixtures/sample.tesc @@ -1,5 +1,5 @@ layout(vertices = 4) out; void main() { - gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; } diff --git a/impeller/fixtures/sample.tese b/impeller/fixtures/sample.tese index b1d3108fd2c3a..b47a8775e4416 100644 --- a/impeller/fixtures/sample.tese +++ b/impeller/fixtures/sample.tese @@ -1,4 +1,4 @@ -layout (quads, equal_spacing, ccw) in; +layout(quads, equal_spacing, ccw) in; void main() { float u = gl_TessCoord.x; @@ -6,9 +6,7 @@ void main() { float v = gl_TessCoord.y; float omv = 1 - v; - gl_Position = - omu * omv * gl_in[0].gl_Position + - u * omv * gl_in[1].gl_Position + - u * v * gl_in[2].gl_Position + - omu * v * gl_in[3].gl_Position; + gl_Position = omu * omv * gl_in[0].gl_Position + + u * omv * gl_in[1].gl_Position + u * v * gl_in[2].gl_Position + + omu * v * gl_in[3].gl_Position; } diff --git a/impeller/fixtures/sample.vert b/impeller/fixtures/sample.vert index fc7e9d1122000..746824ec0adee 100644 --- a/impeller/fixtures/sample.vert +++ b/impeller/fixtures/sample.vert @@ -6,7 +6,8 @@ uniform UniformBufferObject { Uniforms uniforms; -} ubo; +} +ubo; uniform sampler2D world; @@ -18,6 +19,8 @@ in float stuff; out vec4 outStuff; void main() { - gl_Position = ubo.uniforms.projection * ubo.uniforms.view * ubo.uniforms.model * vec4(inPosition22, 1.0) * inAnotherPosition; + gl_Position = ubo.uniforms.projection * ubo.uniforms.view * + ubo.uniforms.model * vec4(inPosition22, 1.0) * + inAnotherPosition; outStuff = texture(world, inPosition); } diff --git a/impeller/fixtures/sample_with_binding.vert b/impeller/fixtures/sample_with_binding.vert index c713700b3536d..97c01fe8359aa 100644 --- a/impeller/fixtures/sample_with_binding.vert +++ b/impeller/fixtures/sample_with_binding.vert @@ -4,9 +4,10 @@ #include "types.h" -layout (set = 3, binding = 17) uniform UniformBufferObject { +layout(set = 3, binding = 17) uniform UniformBufferObject { Uniforms uniforms; -} ubo; +} +ubo; uniform sampler2D world; @@ -18,6 +19,8 @@ in float stuff; out vec4 outStuff; void main() { - gl_Position = ubo.uniforms.projection * ubo.uniforms.view * ubo.uniforms.model * vec4(inPosition22, 1.0) * inAnotherPosition; + gl_Position = ubo.uniforms.projection * ubo.uniforms.view * + ubo.uniforms.model * vec4(inPosition22, 1.0) * + inAnotherPosition; outStuff = texture(world, inPosition); } diff --git a/impeller/fixtures/struct_def_bug.vert b/impeller/fixtures/struct_def_bug.vert index 800dc5358ef17..69d5eb063652e 100644 --- a/impeller/fixtures/struct_def_bug.vert +++ b/impeller/fixtures/struct_def_bug.vert @@ -6,29 +6,30 @@ uniform FrameInfo { mat4 mvp; vec2 atlas_size; vec4 text_color; -} frame_info; +} +frame_info; in vec2 unit_vertex; -in mat4 glyph_position; // <--- Causes multiple slots to be used and is a failure. -in vec2 glyph_size; -in vec2 atlas_position; -in vec2 atlas_glyph_size; +in mat4 + glyph_position; // <--- Causes multiple slots to be used and is a failure. +in vec2 destination_size; +in vec2 source_position; +in vec2 source_glyph_size; out vec2 v_unit_vertex; -out vec2 v_atlas_position; -out vec2 v_atlas_glyph_size; +out vec2 v_source_position; +out vec2 v_source_glyph_size; out vec2 v_atlas_size; out vec4 v_text_color; void main() { - gl_Position = frame_info.mvp - * glyph_position - * vec4(unit_vertex.x * glyph_size.x, - unit_vertex.y * glyph_size.y, 0.0, 1.0); + gl_Position = frame_info.mvp * glyph_position * + vec4(unit_vertex.x * destination_size.x, + unit_vertex.y * destination_size.y, 0.0, 1.0); v_unit_vertex = unit_vertex; - v_atlas_position = atlas_position; - v_atlas_glyph_size = atlas_glyph_size; + v_source_position = source_position; + v_source_glyph_size = source_glyph_size; v_atlas_size = frame_info.atlas_size; v_text_color = frame_info.text_color; } diff --git a/impeller/fixtures/test_texture.vert b/impeller/fixtures/test_texture.vert index 24b7ae6b13b7f..0b8c99e7f7fb9 100644 --- a/impeller/fixtures/test_texture.vert +++ b/impeller/fixtures/test_texture.vert @@ -4,11 +4,11 @@ uniform FrameInfo { mat4 mvp; -} frame_info; +} +frame_info; in vec2 vtx; void main() { gl_Position = frame_info.mvp * vec4(vtx, 0.0, 1.0); - } diff --git a/impeller/geometry/BUILD.gn b/impeller/geometry/BUILD.gn index e8d518950bdf0..a1b511ce9f41b 100644 --- a/impeller/geometry/BUILD.gn +++ b/impeller/geometry/BUILD.gn @@ -39,8 +39,6 @@ impeller_component("geometry") { "type_traits.h", "vector.cc", "vector.h", - "vertices.cc", - "vertices.h", ] deps = [ "//flutter/fml" ] diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 9392b12947cbb..72d09f1ab5b21 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -1646,21 +1646,6 @@ TEST(GeometryTest, PathPolylineDuplicatesAreRemovedForSameContour) { ASSERT_EQ(polyline.points[6], Point(0, 100)); } -TEST(GeometryTest, VerticesConstructorAndGetters) { - std::vector points = {Point(1, 2), Point(2, 3), Point(3, 4)}; - std::vector indices = {0, 1, 2}; - std::vector colors = {Color::White(), Color::White(), Color::White()}; - - Vertices vertices = Vertices(points, indices, colors, VertexMode::kTriangle, - Rect(0, 0, 4, 4)); - - ASSERT_EQ(vertices.GetBoundingBox().value(), Rect(0, 0, 4, 4)); - ASSERT_EQ(vertices.GetPositions(), points); - ASSERT_EQ(vertices.GetIndices(), indices); - ASSERT_EQ(vertices.GetColors(), colors); - ASSERT_EQ(vertices.GetMode(), VertexMode::kTriangle); -} - TEST(GeometryTest, MatrixPrinting) { { std::stringstream stream; @@ -1818,6 +1803,75 @@ TEST(GeometryTest, Gradient) { auto gradient = CreateGradientBuffer(colors, stops); ASSERT_EQ(gradient.texture_size, 1024u); + ASSERT_EQ(gradient.color_bytes.size(), 1024u * 4); + } +} + +TEST(GeometryTest, GradientSSBO) { + { + // Simple 2 color gradient produces std::nullopt, as original + // color vector should be used. + std::vector colors = {Color::Red(), Color::Blue()}; + std::vector stops = {0.0, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient, std::nullopt); + } + + { + // Gradient with duplicate stops does not create an empty texture. + std::vector colors = {Color::Red(), Color::Yellow(), Color::Black(), + Color::Blue()}; + std::vector stops = {0.0, 0.25, 0.25, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + ASSERT_EQ(gradient.value().size(), 5u); + } + + { + // Simple N color gradient produces color buffer containing exactly those + // values. + std::vector colors = {Color::Red(), Color::Blue(), Color::Green(), + Color::White()}; + std::vector stops = {0.0, 0.33, 0.66, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient, std::nullopt); + } + + { + // Gradient with color stops will lerp and scale buffer. + std::vector colors = {Color::Red(), Color::Blue(), Color::Green()}; + std::vector stops = {0.0, 0.25, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + std::vector lerped_colors = { + Color::Red(), + Color::Blue(), + Color::lerp(Color::Blue(), Color::Green(), 0.3333), + Color::lerp(Color::Blue(), Color::Green(), 0.6666), + Color::Green(), + }; + + ASSERT_COLORS_NEAR(gradient.value(), lerped_colors); + ASSERT_EQ(gradient.value().size(), 5u); + } + + { + // Gradient size is capped at 1024. + std::vector colors = {}; + std::vector stops = {}; + for (auto i = 0u; i < 1025; i++) { + colors.push_back(Color::Blue()); + stops.push_back(i / 1025.0); + } + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient.value().size(), 1024u); } } diff --git a/impeller/geometry/geometry_unittests.h b/impeller/geometry/geometry_unittests.h index 4407ad85479c5..d2c63fc2fe24d 100644 --- a/impeller/geometry/geometry_unittests.h +++ b/impeller/geometry/geometry_unittests.h @@ -11,7 +11,6 @@ #include "impeller/geometry/rect.h" #include "impeller/geometry/size.h" #include "impeller/geometry/vector.h" -#include "impeller/geometry/vertices.h" inline bool NumberNear(double a, double b) { static const double epsilon = 1e-3; @@ -131,6 +130,23 @@ inline ::testing::AssertionResult ColorBufferNear( return ::testing::AssertionSuccess(); } +inline ::testing::AssertionResult ColorsNear(std::vector a, + std::vector b) { + if (a.size() != b.size()) { + return ::testing::AssertionFailure() << "Colors length does not match"; + } + for (auto i = 0u; i < b.size(); i++) { + auto equal = + NumberNear(a[i].red, b[i].red) && NumberNear(a[i].green, b[i].green) && + NumberNear(a[i].blue, b[i].blue) && NumberNear(a[i].alpha, b[i].alpha); + + if (!equal) { + ::testing::AssertionFailure() << "Colors are not equal."; + } + } + return ::testing::AssertionSuccess(); +} + #define ASSERT_MATRIX_NEAR(a, b) ASSERT_PRED2(&::MatrixNear, a, b) #define ASSERT_QUATERNION_NEAR(a, b) ASSERT_PRED2(&::QuaternionNear, a, b) #define ASSERT_RECT_NEAR(a, b) ASSERT_PRED2(&::RectNear, a, b) @@ -141,3 +157,4 @@ inline ::testing::AssertionResult ColorBufferNear( #define ASSERT_SIZE_NEAR(a, b) ASSERT_PRED2(&::SizeNear, a, b) #define ASSERT_ARRAY_4_NEAR(a, b) ASSERT_PRED2(&::Array4Near, a, b) #define ASSERT_COLOR_BUFFER_NEAR(a, b) ASSERT_PRED2(&::ColorBufferNear, a, b) +#define ASSERT_COLORS_NEAR(a, b) ASSERT_PRED2(&::ColorsNear, a, b) diff --git a/impeller/geometry/gradient.cc b/impeller/geometry/gradient.cc index 086d90c2e68b4..e668827e80ea4 100644 --- a/impeller/geometry/gradient.cc +++ b/impeller/geometry/gradient.cc @@ -9,12 +9,12 @@ namespace impeller { -static void AppendColor(const Color& color, std::vector* colors) { +static void AppendColor(const Color& color, GradientData* data) { auto converted = color.ToR8G8B8A8(); - colors->push_back(converted[0]); - colors->push_back(converted[1]); - colors->push_back(converted[2]); - colors->push_back(converted[3]); + data->color_bytes.push_back(converted[0]); + data->color_bytes.push_back(converted[1]); + data->color_bytes.push_back(converted[2]); + data->color_bytes.push_back(converted[3]); } GradientData CreateGradientBuffer(const std::vector& colors, @@ -43,12 +43,15 @@ GradientData CreateGradientBuffer(const std::vector& colors, texture_size = std::min( static_cast(std::round(1.0 / minimum_delta)) + 1, 1024u); } - std::vector color_stop_channels; - color_stop_channels.reserve(texture_size * 4); + GradientData data = { + .color_bytes = {}, + .texture_size = texture_size, + }; + data.color_bytes.reserve(texture_size * 4); if (texture_size == colors.size() && colors.size() <= 1024) { for (auto i = 0u; i < colors.size(); i++) { - AppendColor(colors[i], &color_stop_channels); + AppendColor(colors[i], &data); } } else { Color previous_color = colors[0]; @@ -56,7 +59,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto previous_color_index = 0; // The first index is always equal to the first color, exactly. - AppendColor(previous_color, &color_stop_channels); + AppendColor(previous_color, &data); for (auto i = 1u; i < texture_size - 1; i++) { auto scaled_i = i / (texture_size - 1.0); @@ -64,7 +67,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto next_stop = stops[previous_color_index + 1]; // We're almost exactly equal to the next stop. if (ScalarNearlyEqual(scaled_i, next_stop)) { - AppendColor(next_color, &color_stop_channels); + AppendColor(next_color, &data); previous_color = next_color; previous_stop = next_stop; @@ -74,7 +77,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); auto mixed_color = Color::lerp(previous_color, next_color, t); - AppendColor(mixed_color, &color_stop_channels); + AppendColor(mixed_color, &data); } else { // We've slightly overshot the previous stop. previous_color = next_color; @@ -86,16 +89,89 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); auto mixed_color = Color::lerp(previous_color, next_color, t); - AppendColor(mixed_color, &color_stop_channels); + AppendColor(mixed_color, &data); } } // The last index is always equal to the last color, exactly. - AppendColor(colors.back(), &color_stop_channels); + AppendColor(colors.back(), &data); } - return GradientData{ - .color_bytes = std::move(color_stop_channels), - .texture_size = texture_size, - }; + return data; +} + +std::optional> CreateGradientColors( + const std::vector& colors, + const std::vector& stops) { + FML_DCHECK(stops.size() == colors.size()); + + if (stops.size() == 2) { + // Use original buffer. + return std::nullopt; + } + + auto minimum_delta = 1.0; + for (size_t i = 1; i < stops.size(); i++) { + auto value = stops[i] - stops[i - 1]; + // Smaller than kEhCloseEnough + if (value < 0.0001) { + continue; + } + if (value < minimum_delta) { + minimum_delta = value; + } + } + // Avoid creating buffers that are absurdly large due to stops that are + // very close together. + uint32_t color_count = std::min( + static_cast(std::round(1.0 / minimum_delta)) + 1, 1024u); + + if (color_count == colors.size()) { + // Use original buffer. + return std::nullopt; + } + + std::vector data; + data.reserve(color_count); + + Color previous_color = colors[0]; + auto previous_stop = 0.0; + auto previous_color_index = 0; + + // The first index is always equal to the first color, exactly. + data.push_back(colors[0]); + + for (auto i = 1u; i < color_count - 1; i++) { + auto scaled_i = i / (color_count - 1.0); + Color next_color = colors[previous_color_index + 1]; + auto next_stop = stops[previous_color_index + 1]; + // We're almost exactly equal to the next stop. + if (ScalarNearlyEqual(scaled_i, next_stop)) { + data.push_back(next_color); + + previous_color = next_color; + previous_stop = next_stop; + previous_color_index += 1; + } else if (scaled_i < next_stop) { + // We're still between the current stop and the next stop. + auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); + auto mixed_color = Color::lerp(previous_color, next_color, t); + + data.push_back(mixed_color); + } else { + // We've slightly overshot the previous stop. + previous_color = next_color; + previous_stop = next_stop; + previous_color_index += 1; + next_color = colors[previous_color_index + 1]; + auto next_stop = stops[previous_color_index + 1]; + + auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); + auto mixed_color = Color::lerp(previous_color, next_color, t); + data.push_back(mixed_color); + } + } + // The last index is always equal to the last color, exactly. + data.push_back(colors.back()); + return data; } } // namespace impeller diff --git a/impeller/geometry/gradient.h b/impeller/geometry/gradient.h index d9f943de77177..2d8e737adab35 100644 --- a/impeller/geometry/gradient.h +++ b/impeller/geometry/gradient.h @@ -20,8 +20,8 @@ struct GradientData { }; /** - * @brief Populate a vector with the interpolated colors for the linear gradient - * described colors and stops. + * @brief Populate a vector with the interpolated color bytes for the linear + * gradient described by colors and stops. * * @param colors * @param stops @@ -30,4 +30,19 @@ struct GradientData { GradientData CreateGradientBuffer(const std::vector& colors, const std::vector& stops); +/** + * @brief Populate a vector with the interpolated colors for the linear gradient + * described by colors and stops. + * + * If the returned result is std::nullopt, the original color buffer can be used + * instead. + * + * @param colors + * @param stops + * @return GradientData + */ +std::optional> CreateGradientColors( + const std::vector& colors, + const std::vector& stops); + } // namespace impeller diff --git a/impeller/geometry/vertices.cc b/impeller/geometry/vertices.cc deleted file mode 100644 index a93c7c2242cd4..0000000000000 --- a/impeller/geometry/vertices.cc +++ /dev/null @@ -1,73 +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 "vertices.h" - -namespace impeller { - -Vertices::Vertices(std::vector points, - std::vector indices, - std::vector colors, - VertexMode vertex_mode, - Rect bounds) - : positions_(std::move(points)), - indices_(std::move(indices)), - colors_(std::move(colors)), - vertex_mode_(vertex_mode), - bounds_(bounds) { - NormalizeIndices(); -} - -Vertices::~Vertices() = default; - -bool Vertices::IsValid() const { - size_t points_size = positions_.size(); - size_t colors_size = colors_.size(); - - if (colors_size > 0 && colors_size != points_size) { - return false; - } - - return true; -} - -std::optional Vertices::GetBoundingBox() const { - return bounds_; -}; - -std::optional Vertices::GetTransformedBoundingBox( - const Matrix& transform) const { - auto bounds = GetBoundingBox(); - if (!bounds.has_value()) { - return std::nullopt; - } - return bounds->TransformBounds(transform); -}; - -const std::vector& Vertices::GetPositions() const { - return positions_; -} - -const std::vector& Vertices::GetIndices() const { - return indices_; -} - -const std::vector& Vertices::GetColors() const { - return colors_; -} - -VertexMode Vertices::GetMode() const { - return vertex_mode_; -} - -void Vertices::NormalizeIndices() { - if (indices_.size() != 0 || positions_.size() == 0) { - return; - } - for (size_t i = 0; i < positions_.size(); i++) { - indices_.push_back(i); - } -} - -} // namespace impeller diff --git a/impeller/geometry/vertices.h b/impeller/geometry/vertices.h deleted file mode 100644 index b642a8dc8f625..0000000000000 --- a/impeller/geometry/vertices.h +++ /dev/null @@ -1,55 +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. - -#pragma once - -#include -#include - -#include "impeller/geometry/color.h" -#include "impeller/geometry/point.h" -#include "impeller/geometry/rect.h" - -namespace impeller { - -enum class VertexMode { - kTriangle, - kTriangleStrip, -}; - -class Vertices { - public: - Vertices(std::vector positions, - std::vector indices, - std::vector colors, - VertexMode vertex_mode, - Rect bounds); - - ~Vertices(); - - bool IsValid() const; - - std::optional GetBoundingBox() const; - - std::optional GetTransformedBoundingBox(const Matrix& transform) const; - - const std::vector& GetPositions() const; - - const std::vector& GetIndices() const; - - const std::vector& GetColors() const; - - VertexMode GetMode() const; - - private: - std::vector positions_; - std::vector indices_; - std::vector colors_; - VertexMode vertex_mode_; - Rect bounds_; - - void NormalizeIndices(); -}; - -} // namespace impeller diff --git a/impeller/playground/BUILD.gn b/impeller/playground/BUILD.gn index 68ba55aa46045..627160f7def96 100644 --- a/impeller/playground/BUILD.gn +++ b/impeller/playground/BUILD.gn @@ -40,6 +40,7 @@ impeller_component("playground") { public_deps = [ "../entity:entity_shaders", + "../entity:modern_entity_shaders", "../fixtures:shader_fixtures", "../renderer", "imgui:imgui_impeller_backend", diff --git a/impeller/playground/backend/metal/playground_impl_mtl.mm b/impeller/playground/backend/metal/playground_impl_mtl.mm index 1a66beac6c0ab..c400e62a9f7a5 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -15,6 +15,7 @@ #include "flutter/fml/mapping.h" #include "impeller/entity/mtl/entity_shaders.h" +#include "impeller/entity/mtl/modern_shaders.h" #include "impeller/fixtures/mtl/fixtures_shaders.h" #include "impeller/playground/imgui/mtl/imgui_shaders.h" #include "impeller/renderer/backend/metal/context_mtl.h" @@ -33,6 +34,8 @@ return { std::make_shared(impeller_entity_shaders_data, impeller_entity_shaders_length), + std::make_shared(impeller_modern_shaders_data, + impeller_modern_shaders_length), std::make_shared(impeller_fixtures_shaders_data, impeller_fixtures_shaders_length), std::make_shared(impeller_imgui_shaders_data, diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index bcd35f85ecb3b..ca96a816d6f60 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -12,6 +12,7 @@ #include "flutter/fml/logging.h" #include "flutter/fml/mapping.h" #include "impeller/entity/vk/entity_shaders_vk.h" +#include "impeller/entity/vk/modern_shaders_vk.h" #include "impeller/fixtures/vk/fixtures_shaders_vk.h" #include "impeller/playground/imgui/vk/imgui_shaders_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" @@ -26,6 +27,8 @@ ShaderLibraryMappingsForPlayground() { return { std::make_shared(impeller_entity_shaders_vk_data, impeller_entity_shaders_vk_length), + std::make_shared(impeller_modern_shaders_vk_data, + impeller_modern_shaders_vk_length), std::make_shared( impeller_fixtures_shaders_vk_data, impeller_fixtures_shaders_vk_length), diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index e6234c642038e..9ecd91cec6324 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -137,4 +137,14 @@ bool ContextGLES::SupportsOffscreenMSAA() const { return false; } +// |Context| +const BackendFeatures& ContextGLES::GetBackendFeatures() const { + return kLegacyBackendFeatures; +} + +// |Context| +PixelFormat ContextGLES::GetColorAttachmentPixelFormat() const { + return PixelFormat::kR8G8B8A8UNormInt; +} + } // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 138843a7fb7a3..4c841462ca773 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -73,6 +73,12 @@ class ContextGLES final : public Context, // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + + // |Context| + PixelFormat GetColorAttachmentPixelFormat() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextGLES); }; diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index 1ba4740d09525..df6089f618e3f 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -76,6 +76,9 @@ class ContextMTL final : public Context, // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + std::shared_ptr CreateCommandBufferInQueue( id queue) const; diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 379b7cf52fb5f..faedec8e5bf2b 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -247,4 +247,9 @@ return true; } +// |Context| +const BackendFeatures& ContextMTL::GetBackendFeatures() const { + return kModernBackendFeatures; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index cfe7f5533e78b..2d0caad238ebe 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -115,7 +115,8 @@ std::shared_ptr AllocatorVK::OnCreateTexture( image_create_info.tiling = vk::ImageTiling::eOptimal; image_create_info.initialLayout = vk::ImageLayout::eUndefined; image_create_info.usage = vk::ImageUsageFlagBits::eSampled | - vk::ImageUsageFlagBits::eColorAttachment; + vk::ImageUsageFlagBits::eColorAttachment | + vk::ImageUsageFlagBits::eTransferDst; VmaAllocationCreateInfo alloc_create_info = {}; alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO; @@ -164,14 +165,20 @@ std::shared_ptr AllocatorVK::OnCreateTexture( } auto image_view = static_cast(img_view_res.value); + auto staging_buffer = + CreateHostVisibleDeviceAllocation(desc.GetByteSizeOfBaseMipLevel()); auto texture_info = std::make_unique(TextureInfoVK{ .backing_type = TextureBackingTypeVK::kAllocatedTexture, .allocated_texture = { - .allocator = &allocator_, - .allocation = allocation, - .allocation_info = allocation_info, + .staging_buffer = staging_buffer, + .backing_allocation = + { + .allocator = &allocator_, + .allocation = allocation, + .allocation_info = allocation_info, + }, .image = img, .image_view = image_view, }, @@ -184,6 +191,14 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( const DeviceBufferDescriptor& desc) { // TODO (kaushikiska): consider optimizing the usage flags based on // StorageMode. + auto device_allocation = std::make_unique( + CreateHostVisibleDeviceAllocation(desc.size)); + return std::make_shared(desc, context_, + std::move(device_allocation)); +} + +DeviceBufferAllocationVK AllocatorVK::CreateHostVisibleDeviceAllocation( + size_t size) { auto buffer_create_info = static_cast( vk::BufferCreateInfo() .setUsage(vk::BufferUsageFlagBits::eVertexBuffer | @@ -191,7 +206,7 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst) - .setSize(desc.size) + .setSize(size) .setSharingMode(vk::SharingMode::eExclusive)); VmaAllocationCreateInfo allocCreateInfo = {}; @@ -207,15 +222,27 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( &buffer, &buffer_allocation, &buffer_allocation_info)}; if (result != vk::Result::eSuccess) { - VALIDATION_LOG << "Unable to allocate a device buffer"; - return nullptr; + VALIDATION_LOG << "Unable to allocate a device buffer: " + << vk::to_string(result); + return {}; } - auto device_allocation = std::make_unique( - allocator_, buffer, buffer_allocation, buffer_allocation_info); + VkMemoryPropertyFlags memory_props; + vmaGetAllocationMemoryProperties(allocator_, buffer_allocation, + &memory_props); + if (!(memory_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + VALIDATION_LOG << "Unable to create host visible device buffer."; + } - return std::make_shared(desc, context_, - std::move(device_allocation)); + return DeviceBufferAllocationVK{ + .buffer = vk::Buffer{buffer}, + .backing_allocation = + { + .allocator = &allocator_, + .allocation = buffer_allocation, + .allocation_info = buffer_allocation_info, + }, + }; } // |Allocator| @@ -225,4 +252,5 @@ ISize AllocatorVK::GetMaxTextureSizeSupported() const { // https://registry.khronos.org/vulkan/specs/1.2-extensions/html/vkspec.html#limits-minmax return {4096, 4096}; } + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index 595a0b838ec96..02b76623407e9 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -9,6 +9,7 @@ #include "flutter/vulkan/procs/vulkan_proc_table.h" #include "impeller/renderer/allocator.h" #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/device_buffer_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include @@ -51,6 +52,8 @@ class AllocatorVK final : public Allocator { // |Allocator| ISize GetMaxTextureSizeSupported() const override; + DeviceBufferAllocationVK CreateHostVisibleDeviceAllocation(size_t size); + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorVK); }; diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index e2002204cd13c..2d4ebbe910ec9 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -25,6 +25,7 @@ #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" #include "impeller/renderer/backend/vulkan/swapchain_details_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/backend_features.h" VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE @@ -596,4 +597,8 @@ PixelFormat ContextVK::GetColorAttachmentPixelFormat() const { return ToPixelFormat(surface_format_); } +const BackendFeatures& ContextVK::GetBackendFeatures() const { + return kModernBackendFeatures; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 44806548cd5af..ef8a5661564ee 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -145,6 +145,9 @@ class ContextVK final : public Context, public BackendCast { // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextVK); }; diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.cc b/impeller/renderer/backend/vulkan/device_buffer_vk.cc index 3951864d701fe..92c670da72df1 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.cc @@ -9,30 +9,12 @@ namespace impeller { -DeviceBufferAllocationVK::DeviceBufferAllocationVK( - const VmaAllocator& allocator, - VkBuffer buffer, - VmaAllocation allocation, - VmaAllocationInfo allocation_info) - : allocator_(allocator), - buffer_(buffer), - allocation_(allocation), - allocation_info_(allocation_info) {} - -DeviceBufferAllocationVK::~DeviceBufferAllocationVK() { - if (buffer_) { - // https://github.com/flutter/flutter/issues/112387 - // This buffer can be freed once the command buffer is disposed. - // vmaDestroyBuffer(allocator_, buffer_, allocation_); - } +void* DeviceBufferAllocationVK::GetMapping() const { + return backing_allocation.allocation_info.pMappedData; } vk::Buffer DeviceBufferAllocationVK::GetBufferHandle() const { - return buffer_; -} - -void* DeviceBufferAllocationVK::GetMapping() const { - return allocation_info_.pMappedData; + return buffer; } DeviceBufferVK::DeviceBufferVK( diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.h b/impeller/renderer/backend/vulkan/device_buffer_vk.h index 59aa773b3a15b..da8fd8a729e3d 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.h @@ -13,26 +13,22 @@ namespace impeller { -class DeviceBufferAllocationVK { - public: - DeviceBufferAllocationVK(const VmaAllocator& allocator, - VkBuffer buffer, - VmaAllocation allocation, - VmaAllocationInfo allocation_info); - - ~DeviceBufferAllocationVK(); +// https://github.com/flutter/flutter/issues/112387 +// This buffer can be freed once the command buffer is disposed. +// vmaDestroyBuffer(allocator_, buffer_, allocation_); +struct BackingAllocationVK { + VmaAllocator* allocator = nullptr; + VmaAllocation allocation = nullptr; + VmaAllocationInfo allocation_info = {}; +}; - vk::Buffer GetBufferHandle() const; +struct DeviceBufferAllocationVK { + vk::Buffer buffer = VK_NULL_HANDLE; + BackingAllocationVK backing_allocation = {}; void* GetMapping() const; - private: - const VmaAllocator& allocator_; - vk::Buffer buffer_; - VmaAllocation allocation_; - VmaAllocationInfo allocation_info_; - - FML_DISALLOW_COPY_AND_ASSIGN(DeviceBufferAllocationVK); + vk::Buffer GetBufferHandle() const; }; class DeviceBufferVK final : public DeviceBuffer, diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index d5d46b8c3c873..8ee31b70ea267 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -125,6 +125,12 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { } } + if (!TransitionImageLayout(frame_num, tex_info.swapchain_image->GetImage(), + vk::ImageLayout::eUndefined, + vk::ImageLayout::eColorAttachmentOptimal)) { + return false; + } + command_buffer_->endRenderPass(); return const_cast(this)->EndCommandBuffer(frame_num); @@ -312,12 +318,20 @@ bool RenderPassVK::UpdateDescriptorSets(uint32_t frame_num, if (!TransitionImageLayout(frame_num, texture_vk.GetImage(), vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral)) { + vk::ImageLayout::eTransferDstOptimal)) { + return false; + } + + CopyBufferToImage(frame_num, texture_vk); + + if (!TransitionImageLayout(frame_num, texture_vk.GetImage(), + vk::ImageLayout::eTransferDstOptimal, + vk::ImageLayout::eShaderReadOnlyOptimal)) { return false; } vk::DescriptorImageInfo desc_image_info; - desc_image_info.setImageLayout(vk::ImageLayout::eGeneral); + desc_image_info.setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal); desc_image_info.setSampler(sampler_vk.GetSamplerVK()); desc_image_info.setImageView(texture_vk.GetImageView()); image_infos.push_back(desc_image_info); @@ -404,8 +418,10 @@ bool RenderPassVK::TransitionImageLayout(uint32_t frame_num, vk::ImageMemoryBarrier barrier = vk::ImageMemoryBarrier() - .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead) - .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite) + .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentWrite | + vk::AccessFlagBits::eTransferWrite) + .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead | + vk::AccessFlagBits::eShaderRead) .setOldLayout(layout_old) .setNewLayout(layout_new) .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) @@ -418,10 +434,9 @@ bool RenderPassVK::TransitionImageLayout(uint32_t frame_num, .setLevelCount(1) .setBaseArrayLayer(0) .setLayerCount(1)); - transition_cmd->pipelineBarrier( - vk::PipelineStageFlagBits::eColorAttachmentOutput, - vk::PipelineStageFlagBits::eColorAttachmentOutput, {}, nullptr, nullptr, - barrier); + transition_cmd->pipelineBarrier(vk::PipelineStageFlagBits::eAllGraphics, + vk::PipelineStageFlagBits::eAllGraphics, {}, + nullptr, nullptr, barrier); res = transition_cmd->end(); if (res != vk::Result::eSuccess) { @@ -433,4 +448,60 @@ bool RenderPassVK::TransitionImageLayout(uint32_t frame_num, return true; } +bool RenderPassVK::CopyBufferToImage(uint32_t frame_num, + const TextureVK& texture_vk) const { + auto pool = command_buffer_.getPool(); + vk::CommandBufferAllocateInfo alloc_info = + vk::CommandBufferAllocateInfo() + .setCommandPool(pool) + .setLevel(vk::CommandBufferLevel::ePrimary) + .setCommandBufferCount(1); + auto cmd_buf_res = device_.allocateCommandBuffersUnique(alloc_info); + if (cmd_buf_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to allocate command buffer: " + << vk::to_string(cmd_buf_res.result); + return false; + } + + auto copy_cmd = std::move(cmd_buf_res.value[0]); + + const auto& size = texture_vk.GetTextureDescriptor().size; + + // actual copy happens here + vk::BufferImageCopy region = + vk::BufferImageCopy() + .setBufferOffset(0) + .setBufferRowLength(0) + .setBufferImageHeight(0) + .setImageSubresource( + vk::ImageSubresourceLayers() + .setAspectMask(vk::ImageAspectFlagBits::eColor) + .setMipLevel(0) + .setBaseArrayLayer(0) + .setLayerCount(1)) + .setImageOffset(vk::Offset3D(0, 0, 0)) + .setImageExtent(vk::Extent3D(size.width, size.height, 1)); + + vk::CommandBufferBeginInfo begin_info; + auto res = copy_cmd->begin(begin_info); + + if (res != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to begin command buffer: " << vk::to_string(res); + return false; + } + + copy_cmd->copyBufferToImage(texture_vk.GetStagingBuffer(), + texture_vk.GetImage(), + vk::ImageLayout::eTransferDstOptimal, region); + + res = copy_cmd->end(); + if (res != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res); + return false; + } + + surface_producer_->QueueCommandBuffer(frame_num, std::move(copy_cmd)); + return true; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index 79227696af038..9bf05412b5eee 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -4,7 +4,6 @@ #pragma once -#include #include "flutter/fml/macros.h" #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" @@ -12,8 +11,6 @@ #include "impeller/renderer/command.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" -#include "vulkan/vulkan_enums.hpp" -#include "vulkan/vulkan_structs.hpp" namespace impeller { @@ -77,6 +74,8 @@ class RenderPassVK final : public RenderPass { vk::ImageLayout layout_old, vk::ImageLayout layout_new) const; + bool CopyBufferToImage(uint32_t frame_num, const TextureVK& texture_vk) const; + FML_DISALLOW_COPY_AND_ASSIGN(RenderPassVK); }; diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc index e3c25391e8a08..4faa15f3ea1d8 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_vk.cc @@ -16,7 +16,8 @@ TextureVK::TextureVK(TextureDescriptor desc, TextureVK::~TextureVK() { if (!IsWrapped() && IsValid()) { const auto& texture = texture_info_->allocated_texture; - vmaDestroyImage(*texture.allocator, texture.image, texture.allocation); + vmaDestroyImage(*texture.backing_allocation.allocator, texture.image, + texture.backing_allocation.allocation); } } @@ -45,7 +46,7 @@ bool TextureVK::OnSetContents(const uint8_t* contents, } // currently we are only supporting 2d textures, no cube textures etc. - auto mapping = texture_info_->allocated_texture.allocation_info.pMappedData; + auto mapping = texture_info_->allocated_texture.staging_buffer.GetMapping(); if (mapping) { memcpy(mapping, contents, length); @@ -107,4 +108,17 @@ vk::Image TextureVK::GetImage() const { } } +vk::Buffer TextureVK::GetStagingBuffer() const { + switch (texture_info_->backing_type) { + case TextureBackingTypeVK::kUnknownType: + FML_CHECK(false) << "Unknown texture backing type"; + return nullptr; + case TextureBackingTypeVK::kAllocatedTexture: + return texture_info_->allocated_texture.staging_buffer.GetBufferHandle(); + case TextureBackingTypeVK::kWrappedTexture: + FML_CHECK(false) << "Wrapped textures do not have staging buffers"; + return nullptr; + } +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/texture_vk.h b/impeller/renderer/backend/vulkan/texture_vk.h index 9134894ba801e..08dd3769e22d9 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.h +++ b/impeller/renderer/backend/vulkan/texture_vk.h @@ -7,6 +7,7 @@ #include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/device_buffer_vk.h" #include "impeller/renderer/backend/vulkan/swapchain_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/texture.h" @@ -25,9 +26,8 @@ struct WrappedTextureInfoVK { }; struct AllocatedTextureInfoVK { - VmaAllocator* allocator = nullptr; - VmaAllocation allocation = nullptr; - VmaAllocationInfo allocation_info = {}; + DeviceBufferAllocationVK staging_buffer = {}; + BackingAllocationVK backing_allocation = {}; VkImage image = VK_NULL_HANDLE; VkImageView image_view = VK_NULL_HANDLE; }; @@ -55,6 +55,8 @@ class TextureVK final : public Texture, public BackendCast { vk::ImageView GetImageView() const; + vk::Buffer GetStagingBuffer() const; + TextureInfoVK* GetTextureInfo() const; private: diff --git a/impeller/renderer/backend_features.h b/impeller/renderer/backend_features.h new file mode 100644 index 0000000000000..f8ea75b134a50 --- /dev/null +++ b/impeller/renderer/backend_features.h @@ -0,0 +1,21 @@ +// 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. + +#pragma once + +namespace impeller { + +/// @brief A struct for describing available backend features for runtime +/// selection. +struct BackendFeatures { + bool ssbo_support; +}; + +/// @brief feature sets available on most but not all modern hardware. +constexpr BackendFeatures kModernBackendFeatures = {.ssbo_support = true}; + +/// @brief Lowest common denominator feature sets. +constexpr BackendFeatures kLegacyBackendFeatures = {.ssbo_support = false}; + +} // namespace impeller diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 8ba839b8612c0..9d0fd7113a67e 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -8,6 +8,7 @@ #include #include "flutter/fml/macros.h" +#include "impeller/renderer/backend_features.h" #include "impeller/renderer/formats.h" namespace impeller { @@ -52,6 +53,8 @@ class Context : public std::enable_shared_from_this { virtual bool SupportsOffscreenMSAA() const = 0; + virtual const BackendFeatures& GetBackendFeatures() const = 0; + protected: Context(); diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index ef196a0eec740..7c13412a384fa 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -192,7 +192,7 @@ RenderTarget RenderTarget::CreateOffscreen(const Context& context, TextureDescriptor color_tex0; color_tex0.storage_mode = color_storage_mode; - color_tex0.format = PixelFormat::kDefaultColor; + color_tex0.format = context.GetColorAttachmentPixelFormat(); color_tex0.size = size; color_tex0.usage = static_cast(TextureUsage::kRenderTarget) | static_cast(TextureUsage::kShaderRead); @@ -257,7 +257,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( color0_tex_desc.storage_mode = color_storage_mode; color0_tex_desc.type = TextureType::kTexture2DMultisample; color0_tex_desc.sample_count = SampleCount::kCount4; - color0_tex_desc.format = PixelFormat::kDefaultColor; + color0_tex_desc.format = context.GetColorAttachmentPixelFormat(); color0_tex_desc.size = size; color0_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); @@ -274,7 +274,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( TextureDescriptor color0_resolve_tex_desc; color0_resolve_tex_desc.storage_mode = color_resolve_storage_mode; - color0_resolve_tex_desc.format = PixelFormat::kDefaultColor; + color0_resolve_tex_desc.format = context.GetColorAttachmentPixelFormat(); color0_resolve_tex_desc.size = size; color0_resolve_tex_desc.usage = static_cast(TextureUsage::kRenderTarget) | diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 38495962cdfed..aeb3f162a172d 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -280,6 +280,11 @@ template("impellerc") { "$shader_target_flag", ] + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + args += [ "--gles-language-version=$gles_language_version" ] + } + if (json) { args += [ "--json" ] } @@ -459,6 +464,9 @@ template("impeller_shaders_gles") { impellerc(impellerc_gles) { shaders = invoker.shaders sl_file_extension = "gles" + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } # Metal reflectors generate a superset of information. if (impeller_enable_metal || impeller_enable_vulkan) { @@ -571,6 +579,9 @@ template("impeller_shaders") { gles_shaders = "gles_$target_name" impeller_shaders_gles(gles_shaders) { name = invoker.name + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } if (defined(invoker.gles_exclusions)) { shaders = invoker.shaders - invoker.gles_exclusions } else { diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index c1b6405bc193b..1641171f56a75 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -71,15 +71,19 @@ static size_t PairsFitInAtlasOfSize(const FontGlyphPair::Vector& pairs, glyph_positions.clear(); glyph_positions.reserve(pairs.size()); + // TODO(114563): We might be able to remove this per-glyph padding if we fix + // the underlying causes of the overlap. + constexpr auto padding = 2; + for (size_t i = 0; i < pairs.size(); i++) { const auto& pair = pairs[i]; const auto glyph_size = ISize::Ceil(pair.font.GetMetrics().GetBoundingBox().size * pair.font.GetMetrics().scale); SkIPoint16 location_in_atlas; - if (!rect_packer->addRect(glyph_size.width, // - glyph_size.height, // - &location_in_atlas // + if (!rect_packer->addRect(glyph_size.width + padding, // + glyph_size.height + padding, // + &location_in_atlas // )) { return pairs.size() - i; } diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 30104639e7e55..b039e67ff1030 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -520,6 +520,7 @@ class SceneBuilder extends NativeFieldWrapperClass1 { /// See [pop] for details about the operation stack. ImageFilterEngineLayer pushImageFilter( ImageFilter filter, { + Offset offset = Offset.zero, ImageFilterEngineLayer? oldLayer, }) { assert(filter != null); @@ -527,14 +528,14 @@ class SceneBuilder extends NativeFieldWrapperClass1 { final _ImageFilter nativeFilter = filter._toNativeImageFilter(); assert(nativeFilter != null); final EngineLayer engineLayer = EngineLayer._(); - _pushImageFilter(engineLayer, nativeFilter, oldLayer?._nativeLayer); + _pushImageFilter(engineLayer, nativeFilter, offset.dx, offset.dy, oldLayer?._nativeLayer); final ImageFilterEngineLayer layer = ImageFilterEngineLayer._(engineLayer); assert(_debugPushLayer(layer)); return layer; } - @FfiNative, Handle, Pointer, Handle)>('SceneBuilder::pushImageFilter') - external void _pushImageFilter(EngineLayer outEngineLayer, _ImageFilter filter, EngineLayer? oldLayer); + @FfiNative, Handle, Pointer, Double, Double, Handle)>('SceneBuilder::pushImageFilter') + external void _pushImageFilter(EngineLayer outEngineLayer, _ImageFilter filter, double dx, double dy, EngineLayer? oldLayer); /// Pushes a backdrop filter operation onto the operation stack. /// diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 71419b22f2e0b..6f1c718fa1b5f 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -151,9 +151,11 @@ void SceneBuilder::pushColorFilter(Dart_Handle layer_handle, void SceneBuilder::pushImageFilter(Dart_Handle layer_handle, const ImageFilter* image_filter, + double dx, + double dy, const fml::RefPtr& oldLayer) { - auto layer = - std::make_shared(image_filter->filter()); + auto layer = std::make_shared( + image_filter->filter(), SkPoint::Make(dx, dy)); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); diff --git a/lib/ui/compositing/scene_builder.h b/lib/ui/compositing/scene_builder.h index 1ef7e0773eb7e..f2de29c4802d2 100644 --- a/lib/ui/compositing/scene_builder.h +++ b/lib/ui/compositing/scene_builder.h @@ -74,6 +74,8 @@ class SceneBuilder : public RefCountedDartWrappable { const fml::RefPtr& oldLayer); void pushImageFilter(Dart_Handle layer_handle, const ImageFilter* image_filter, + double dx, + double dy, const fml::RefPtr& oldLayer); void pushBackdropFilter(Dart_Handle layer_handle, ImageFilter* filter, diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index 5199821389311..0410926e68334 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -174,7 +174,7 @@ typedef CanvasPath Path; V(EngineLayer, dispose, 1) \ V(FragmentProgram, initFromAsset, 2) \ V(ReusableFragmentShader, Dispose, 1) \ - V(ReusableFragmentShader, SetSampler, 3) \ + V(ReusableFragmentShader, SetImageSampler, 3) \ V(ReusableFragmentShader, ValidateSamplers, 1) \ V(Gradient, initLinear, 6) \ V(Gradient, initRadial, 8) \ diff --git a/lib/ui/fixtures/shaders/general_shaders/blue_green_sampler.frag b/lib/ui/fixtures/shaders/general_shaders/blue_green_sampler.frag index 4d71cbb91c216..8cff5d531da58 100644 --- a/lib/ui/fixtures/shaders/general_shaders/blue_green_sampler.frag +++ b/lib/ui/fixtures/shaders/general_shaders/blue_green_sampler.frag @@ -6,9 +6,9 @@ precision highp float; -layout ( location = 0 ) out vec4 oColor; +layout(location = 0) out vec4 oColor; -layout ( location = 0 ) uniform sampler2D iChild; +layout(location = 0) uniform sampler2D iChild; void main() { // iChild1 is an image that is half blue, half green, @@ -16,4 +16,3 @@ void main() { oColor = texture(iChild, vec2(1, 0)); oColor.a = 1.0; } - diff --git a/lib/ui/fixtures/shaders/general_shaders/children_and_uniforms.frag b/lib/ui/fixtures/shaders/general_shaders/children_and_uniforms.frag index 44928b864cad3..41bb1556535e3 100644 --- a/lib/ui/fixtures/shaders/general_shaders/children_and_uniforms.frag +++ b/lib/ui/fixtures/shaders/general_shaders/children_and_uniforms.frag @@ -6,12 +6,12 @@ precision highp float; -layout ( location = 0 ) out vec4 color; +layout(location = 0) out vec4 color; -layout ( location = 0 ) uniform sampler2D child1; -layout ( location = 1 ) uniform float a; -layout ( location = 2 ) uniform sampler2D child2; -layout ( location = 3 ) uniform float b; +layout(location = 0) uniform sampler2D child1; +layout(location = 1) uniform float a; +layout(location = 2) uniform sampler2D child2; +layout(location = 3) uniform float b; void main() { // child1 is a 10x10 image where the left half is blue and the right @@ -23,4 +23,3 @@ void main() { color = c1 * c2; } - diff --git a/lib/ui/fixtures/shaders/general_shaders/functions.frag b/lib/ui/fixtures/shaders/general_shaders/functions.frag index 52bf92dbcc1cb..29201527b7d62 100644 --- a/lib/ui/fixtures/shaders/general_shaders/functions.frag +++ b/lib/ui/fixtures/shaders/general_shaders/functions.frag @@ -6,9 +6,9 @@ precision highp float; -layout ( location = 0 ) out vec4 oColor; +layout(location = 0) out vec4 oColor; -layout ( location = 0 ) uniform float a; // should be 1.0 +layout(location = 0) uniform float a; // should be 1.0 float addA(float x) { return x + a; @@ -27,8 +27,8 @@ float multiParam(float x, float y, float z) { } void main() { - float x = addA(0.0); // x = 0 + 1; - vec3 v3 = composedFunction(x); // v3 = vec3(2, 1, 1); - x = multiParam(v3.x, v3.y, v3.z); // x = 2 * 1 * 1 * 1; - oColor = vec4(0.0, x / 2.0, 0.0, 1.0); // vec4(0, 1, 0, 1); + float x = addA(0.0); // x = 0 + 1; + vec3 v3 = composedFunction(x); // v3 = vec3(2, 1, 1); + x = multiParam(v3.x, v3.y, v3.z); // x = 2 * 1 * 1 * 1; + oColor = vec4(0.0, x / 2.0, 0.0, 1.0); // vec4(0, 1, 0, 1); } diff --git a/lib/ui/fixtures/shaders/general_shaders/no_builtin_redefinition.frag b/lib/ui/fixtures/shaders/general_shaders/no_builtin_redefinition.frag index 4e74fe27b86b2..ae3fa0c94c9bd 100644 --- a/lib/ui/fixtures/shaders/general_shaders/no_builtin_redefinition.frag +++ b/lib/ui/fixtures/shaders/general_shaders/no_builtin_redefinition.frag @@ -6,9 +6,9 @@ precision highp float; -layout ( location = 0 ) out vec4 oColor; +layout(location = 0) out vec4 oColor; -layout ( location = 0 ) uniform float a; // should be 1.0 +layout(location = 0) uniform float a; // should be 1.0 float saturate(float x) { return clamp(x, 0.0, 1.0); @@ -31,8 +31,8 @@ float multiParam(float x, float y, float z) { } void main() { - float x = saturate(addA(0.0)); // x = 0 + 1; - vec3 v3 = composedFunction(x); // v3 = vec3(2, 1, 1); - x = multiParam(v3.x, v3.y, v3.z); // x = 2 * 1 * 1 * 1; - oColor = vec4(0.0, x / 2.0, 0.0, 1.0); // vec4(0, 1, 0, 1); + float x = saturate(addA(0.0)); // x = 0 + 1; + vec3 v3 = composedFunction(x); // v3 = vec3(2, 1, 1); + x = multiParam(v3.x, v3.y, v3.z); // x = 2 * 1 * 1 * 1; + oColor = vec4(0.0, x / 2.0, 0.0, 1.0); // vec4(0, 1, 0, 1); } diff --git a/lib/ui/fixtures/shaders/general_shaders/no_uniforms.frag b/lib/ui/fixtures/shaders/general_shaders/no_uniforms.frag index a88db93039f7d..26a8d7c265934 100644 --- a/lib/ui/fixtures/shaders/general_shaders/no_uniforms.frag +++ b/lib/ui/fixtures/shaders/general_shaders/no_uniforms.frag @@ -9,5 +9,5 @@ precision highp float; layout(location = 0) out vec4 fragColor; void main() { - fragColor = vec4(0.0, 1.0, 0.0, 1.0); + fragColor = vec4(0.0, 1.0, 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/general_shaders/simple.frag b/lib/ui/fixtures/shaders/general_shaders/simple.frag index a221a4f8c2b94..a89fe54cf147e 100644 --- a/lib/ui/fixtures/shaders/general_shaders/simple.frag +++ b/lib/ui/fixtures/shaders/general_shaders/simple.frag @@ -11,5 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4(0.0, a, 0.0, 1.0); + fragColor = vec4(0.0, a, 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/general_shaders/uniform_arrays.frag b/lib/ui/fixtures/shaders/general_shaders/uniform_arrays.frag index c1efea1833672..6a7a3e374fa5f 100644 --- a/lib/ui/fixtures/shaders/general_shaders/uniform_arrays.frag +++ b/lib/ui/fixtures/shaders/general_shaders/uniform_arrays.frag @@ -6,12 +6,12 @@ precision highp float; -layout ( location = 0 ) out vec4 oColor; +layout(location = 0) out vec4 oColor; -layout ( location = 1 ) uniform float floatArray[2]; -layout ( location = 3 ) uniform vec2 vec2Array[2]; -layout ( location = 7 ) uniform vec3 vec3Array[2]; -layout ( location = 13 ) uniform mat2 mat2Array[2]; +layout(location = 1) uniform float floatArray[2]; +layout(location = 3) uniform vec2 vec2Array[2]; +layout(location = 7) uniform vec3 vec3Array[2]; +layout(location = 13) uniform mat2 mat2Array[2]; void main() { vec4 badColor = vec4(1.0, 0, 0, 1.0); @@ -20,16 +20,11 @@ void main() { // The test populates the uniforms with strictly increasing values, so if // out-of-order values are read out of the uniforms, then the bad color that // causes the test to fail is returned. - if (floatArray[0] >= floatArray[1] || - floatArray[1] >= vec2Array[0].x || - vec2Array[0].x >= vec2Array[0].y || - vec2Array[0].y >= vec2Array[1].x || - vec2Array[1].x >= vec2Array[1].y || - vec2Array[1].y >= vec3Array[0].x || - vec3Array[0].x >= vec3Array[0].y || - vec3Array[0].y >= vec3Array[0].z || - vec3Array[0].z >= vec3Array[1].x || - vec3Array[1].x >= vec3Array[1].y || + if (floatArray[0] >= floatArray[1] || floatArray[1] >= vec2Array[0].x || + vec2Array[0].x >= vec2Array[0].y || vec2Array[0].y >= vec2Array[1].x || + vec2Array[1].x >= vec2Array[1].y || vec2Array[1].y >= vec3Array[0].x || + vec3Array[0].x >= vec3Array[0].y || vec3Array[0].y >= vec3Array[0].z || + vec3Array[0].z >= vec3Array[1].x || vec3Array[1].x >= vec3Array[1].y || vec3Array[1].y >= vec3Array[1].z || vec3Array[1].z >= mat2Array[0][0][0] || mat2Array[0][0][0] >= mat2Array[0][0][1] || diff --git a/lib/ui/fixtures/shaders/general_shaders/uniforms.frag b/lib/ui/fixtures/shaders/general_shaders/uniforms.frag index c03032c97b156..dac982c9a4b99 100644 --- a/lib/ui/fixtures/shaders/general_shaders/uniforms.frag +++ b/lib/ui/fixtures/shaders/general_shaders/uniforms.frag @@ -6,11 +6,11 @@ precision highp float; -layout ( location = 0 ) out vec4 oColor; +layout(location = 0) out vec4 oColor; -layout ( location = 0 ) uniform float iFloatUniform; -layout ( location = 1 ) uniform vec2 iVec2Uniform; -layout ( location = 2 ) uniform mat2 iMat2Uniform; +layout(location = 0) uniform float iFloatUniform; +layout(location = 1) uniform vec2 iVec2Uniform; +layout(location = 2) uniform mat2 iMat2Uniform; void main() { oColor = vec4(iFloatUniform, iVec2Uniform, iMat2Uniform[1][1]); diff --git a/lib/ui/fixtures/shaders/general_shaders/uniforms_sorted.frag b/lib/ui/fixtures/shaders/general_shaders/uniforms_sorted.frag index 827fc18ce39a5..2d2d7f6fac280 100644 --- a/lib/ui/fixtures/shaders/general_shaders/uniforms_sorted.frag +++ b/lib/ui/fixtures/shaders/general_shaders/uniforms_sorted.frag @@ -36,7 +36,7 @@ layout(location = 0) out vec4 fragColor; const float PI = 3.1415926535897932384626; const float PI_ROTATE_RIGHT = PI * 0.0078125; const float PI_ROTATE_LEFT = PI * -0.0078125; -const float ONE_THIRD = 1./3.; +const float ONE_THIRD = 1. / 3.; const vec2 TURBULENCE_SCALE = vec2(0.8); float triangle_noise(highp vec2 n) { @@ -50,7 +50,7 @@ float threshold(float v, float l, float h) { return step(l, v) * (1.0 - step(h, v)); } -mat2 rotate2d(vec2 rad){ +mat2 rotate2d(vec2 rad) { return mat2(rad.x, -rad.y, rad.y, rad.x); } @@ -66,7 +66,11 @@ float soft_ring(vec2 uv, vec2 xy, float radius, float thickness, float blur) { return clamp(circle_outer - circle_inner, 0.0, 1.0); } -float circle_grid(vec2 resolution, vec2 p, vec2 xy, vec2 rotation, float cell_diameter) { +float circle_grid(vec2 resolution, + vec2 p, + vec2 xy, + vec2 rotation, + float cell_diameter) { p = rotate2d(rotation) * (xy - p) + xy; p = mod(p, cell_diameter) / resolution; float cell_uv = cell_diameter / resolution.y * 0.5; @@ -85,9 +89,12 @@ float sparkle(vec2 uv, float t) { float turbulence(vec2 uv) { vec2 uv_scale = uv * TURBULENCE_SCALE; - float g1 = circle_grid(TURBULENCE_SCALE, uv_scale, u_circle1, u_rotation1, 0.17); - float g2 = circle_grid(TURBULENCE_SCALE, uv_scale, u_circle2, u_rotation2, 0.2); - float g3 = circle_grid(TURBULENCE_SCALE, uv_scale, u_circle3, u_rotation3, 0.275); + float g1 = + circle_grid(TURBULENCE_SCALE, uv_scale, u_circle1, u_rotation1, 0.17); + float g2 = + circle_grid(TURBULENCE_SCALE, uv_scale, u_circle2, u_rotation2, 0.2); + float g3 = + circle_grid(TURBULENCE_SCALE, uv_scale, u_circle3, u_rotation3, 0.275); float v = (g1 * g1 + g2 - g3) * 0.5; return clamp(0.45 + 0.8 * v, 0.0, 1.0); } @@ -101,33 +108,28 @@ void main() { float radius = u_max_radius * u_radius_scale; float turbulence = turbulence(uv); float ring = soft_ring(p, u_center, radius, 0.05 * u_max_radius, u_blur); - float sparkle = sparkle(density_uv, u_noise_phase) * ring * turbulence * u_sparkle_alpha; - float wave_alpha = soft_circle(p, u_center, radius, u_blur) * u_alpha * u_color.a; + float sparkle = + sparkle(density_uv, u_noise_phase) * ring * turbulence * u_sparkle_alpha; + float wave_alpha = + soft_circle(p, u_center, radius, u_blur) * u_alpha * u_color.a; vec4 wave_color = vec4(u_color.rgb * wave_alpha, wave_alpha); - vec4 sparkle_color = vec4(u_sparkle_color.rgb * u_sparkle_color.a, u_sparkle_color.a); + vec4 sparkle_color = + vec4(u_sparkle_color.rgb * u_sparkle_color.a, u_sparkle_color.a); fragColor = mix(wave_color, sparkle_color, sparkle); vec4 badColor = vec4(1.0, 0, 0, 1.0); vec4 goodColor = vec4(0, 1.0, 0, 1.0); - if (u_color.x > u_alpha || - u_alpha > u_sparkle_color.x || - u_sparkle_color.x > u_sparkle_alpha || - u_sparkle_alpha > u_blur || - u_blur > u_center.x || - u_center.x > u_radius_scale || - u_radius_scale > u_max_radius || - u_max_radius > u_resolution_scale.x || + if (u_color.x > u_alpha || u_alpha > u_sparkle_color.x || + u_sparkle_color.x > u_sparkle_alpha || u_sparkle_alpha > u_blur || + u_blur > u_center.x || u_center.x > u_radius_scale || + u_radius_scale > u_max_radius || u_max_radius > u_resolution_scale.x || u_resolution_scale.x > u_noise_scale.x || - u_noise_scale.x > u_noise_phase || - u_noise_phase > u_circle1.x || - u_circle1.x > u_circle2.x || - u_circle2.x > u_circle3.x || - u_circle3.x > u_rotation1.x || - u_rotation1.x > u_rotation2.x || + u_noise_scale.x > u_noise_phase || u_noise_phase > u_circle1.x || + u_circle1.x > u_circle2.x || u_circle2.x > u_circle3.x || + u_circle3.x > u_rotation1.x || u_rotation1.x > u_rotation2.x || u_rotation2.x > u_rotation3.x) { fragColor = badColor; } else { fragColor = goodColor; } } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/10_fract.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/10_fract.frag index bdf14300f07f1..4c9c443737552 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/10_fract.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/10_fract.frag @@ -11,11 +11,7 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - fract(a), - // 0.25 + 0.75 = 1.0 - fract(a + 1.25) + fract(3.75), - 0.0, - 1.0 - ); + fragColor = vec4(fract(a), + // 0.25 + 0.75 = 1.0 + fract(a + 1.25) + fract(3.75), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/11_radians.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/11_radians.frag index 1a8fd54311ddc..fafdac1ef3a3a 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/11_radians.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/11_radians.frag @@ -11,11 +11,7 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - // 57.2957795131 * pi / 180.0 = 1.0 - float(radians(a * 57.2957795131)), - 0.0, - 1.0 - ); + fragColor = vec4(0.0, + // 57.2957795131 * pi / 180.0 = 1.0 + float(radians(a * 57.2957795131)), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/12_degrees.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/12_degrees.frag index ca185e63435cf..f04cdcfbe4caf 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/12_degrees.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/12_degrees.frag @@ -11,11 +11,7 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - // 0.01745329251 * 180.0 / pi = 1.0 - degrees(a * 0.01745329251), - 0.0, - 1.0 - ); + fragColor = vec4(0.0, + // 0.01745329251 * 180.0 / pi = 1.0 + degrees(a * 0.01745329251), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/13_sin.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/13_sin.frag index 6c89587ea5fc5..0ca8ab798d7d9 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/13_sin.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/13_sin.frag @@ -11,11 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - /* sin(0.0) = 0.0 */ - sin(0.0), - // sin(1.57079632679) = sin(pi / 2.0) = 1.0 - sin(a * 1.57079632679), - 0.0, - 1.0); + fragColor = vec4( + /* sin(0.0) = 0.0 */ + sin(0.0), + // sin(1.57079632679) = sin(pi / 2.0) = 1.0 + sin(a * 1.57079632679), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/14_cos.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/14_cos.frag index 52600b964e2a3..17a478cffbece 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/14_cos.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/14_cos.frag @@ -11,11 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - /* cos(1.57079632679) = cos(pi / 2.0) = 0.0 */ - cos(a * 1.57079632679), - // cos(0.0) = 0.0 - cos(0.0), - 0.0, - 1.0); + fragColor = vec4( + /* cos(1.57079632679) = cos(pi / 2.0) = 0.0 */ + cos(a * 1.57079632679), + // cos(0.0) = 0.0 + cos(0.0), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/15_tan.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/15_tan.frag index c5cbbd406369b..c93ec0d078aa3 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/15_tan.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/15_tan.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // tan(0.0) = 0.0 - tan(0.0), - // tan(1.57079632679) = tan(pi / 4.0) = 1.0 - tan(a * 0.785398163), - 0.0, - 1.0 - ); + fragColor = vec4( + // tan(0.0) = 0.0 + tan(0.0), + // tan(1.57079632679) = tan(pi / 4.0) = 1.0 + tan(a * 0.785398163), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/16_asin.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/16_asin.frag index 92880cda929ab..976c7ddbca04e 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/16_asin.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/16_asin.frag @@ -11,11 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - /* sin(0.0) = 0.0 */ - asin(0.0), - // sin(1.0) = 0.8414709848 - asin(a * 0.8414709848), - 0.0, - 1.0); + fragColor = vec4( + /* sin(0.0) = 0.0 */ + asin(0.0), + // sin(1.0) = 0.8414709848 + asin(a * 0.8414709848), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/17_acos.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/17_acos.frag index 6d0f7eb05f98a..d8f159adab80a 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/17_acos.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/17_acos.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // cos(0.0) = 1.0 - acos(1.0), - // cos(1.0) = 0.54030230586 - acos(a * 0.54030230586), - 0.0, - 1.0 - ); + fragColor = vec4( + // cos(0.0) = 1.0 + acos(1.0), + // cos(1.0) = 0.54030230586 + acos(a * 0.54030230586), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/18_atan.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/18_atan.frag index 68f5b4968a863..e1146c794cd7e 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/18_atan.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/18_atan.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // tan(0.0) = 0.0 - atan(0.0), - // tan(1.0) = 1.55740772465 - atan(a * 1.55740772465), - 0.0, - 1.0 - ); + fragColor = vec4( + // tan(0.0) = 0.0 + atan(0.0), + // tan(1.0) = 1.55740772465 + atan(a * 1.55740772465), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/25_atan2.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/25_atan2.frag index 2e42d9fd9c349..054a5551a475b 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/25_atan2.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/25_atan2.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // tan(0.0 / 1.0) = tan(0.0) = 0.0 - atan(0.0, 1.0), - // tan(3.1148154493 / 2.0) = tan(1.55740772465) = 1.0 - atan(a * 3.1148154493, 2.0), - 0.0, - 1.0 - ); + fragColor = vec4( + // tan(0.0 / 1.0) = tan(0.0) = 0.0 + atan(0.0, 1.0), + // tan(3.1148154493 / 2.0) = tan(1.55740772465) = 1.0 + atan(a * 3.1148154493, 2.0), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/26_pow.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/26_pow.frag index ea808bd7a5794..1a5d26afd98aa 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/26_pow.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/26_pow.frag @@ -11,11 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - pow(2.0, a-1.0) - 1.0, - pow(a * 3.14, 0.0), - 0.0, - 1.0 - ); + fragColor = vec4(pow(2.0, a - 1.0) - 1.0, pow(a * 3.14, 0.0), 0.0, 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/27_exp.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/27_exp.frag index 61f476c7c54ca..e8ca170396692 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/27_exp.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/27_exp.frag @@ -11,12 +11,10 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - // e^0.0 = 1.0 - exp(a * 0.0), - 0.0, - // e^2.0 - 6.38905609893 = 7.38905609893 - 6.38905609893 = 1.0 - exp(a * 2.0) - 6.38905609893 - ); + fragColor = + vec4(0.0, + // e^0.0 = 1.0 + exp(a * 0.0), 0.0, + // e^2.0 - 6.38905609893 = 7.38905609893 - 6.38905609893 = 1.0 + exp(a * 2.0) - 6.38905609893); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/28_log.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/28_log.frag index c4f3b9955cbeb..62b98f5151974 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/28_log.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/28_log.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // e^0.0 = 1.0 - log(a), - // e^1.0 = e - log(a * 2.718281828459), - 0.0, - 1.0 - ); + fragColor = vec4( + // e^0.0 = 1.0 + log(a), + // e^1.0 = e + log(a * 2.718281828459), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/29_exp2.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/29_exp2.frag index d6c4251a892bc..395265100cfb0 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/29_exp2.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/29_exp2.frag @@ -11,13 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - // 2.0^0.0 = 1.0 - exp2(a - 1.0), - 0.0, - // 2.0^3.0 - 7.0 = 8.0 - 7.0 = 1.0 - exp2(a * 3.0) - 7.0 - ); + fragColor = vec4(0.0, + // 2.0^0.0 = 1.0 + exp2(a - 1.0), 0.0, + // 2.0^3.0 - 7.0 = 8.0 - 7.0 = 1.0 + exp2(a * 3.0) - 7.0); } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/30_log2.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/30_log2.frag index 5a1e8579831c1..dfd5b8ced6048 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/30_log2.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/30_log2.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // 2.0^0.0 = 1.0 - log2(a), - // 2.0^1.0 = 2.0 - log2(a * 2.0), - 0.0, - 1.0 - ); + fragColor = vec4( + // 2.0^0.0 = 1.0 + log2(a), + // 2.0^1.0 = 2.0 + log2(a * 2.0), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/31_sqrt.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/31_sqrt.frag index 59892ab260199..c8253ce976754 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/31_sqrt.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/31_sqrt.frag @@ -11,11 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - sqrt(a - 1.0), - sqrt(a), - sqrt(a * 9.0) - 3.0, - 1.0 - ); + fragColor = vec4(sqrt(a - 1.0), sqrt(a), sqrt(a * 9.0) - 3.0, 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/32_inversesqrt.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/32_inversesqrt.frag index d84c38910bda2..b8ff3fbb278f5 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/32_inversesqrt.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/32_inversesqrt.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - // 1.0 / sqrt(1.0) = 1.0 - inversesqrt(a), - 0.0, - // 1.0 / sqrt(4.0) + 0.5 = 1.0 / 2.0 + 0.5 = 1.0 - inversesqrt(a * 4.0) + 0.5 - ); + fragColor = vec4(0.0, + // 1.0 / sqrt(1.0) = 1.0 + inversesqrt(a), 0.0, + // 1.0 / sqrt(4.0) + 0.5 = 1.0 / 2.0 + 0.5 = 1.0 + inversesqrt(a * 4.0) + 0.5); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/37_fmin.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/37_fmin.frag index 9dbea871c9a80..72516fc5381cd 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/37_fmin.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/37_fmin.frag @@ -11,10 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - 1.0 - min(1.0, 1.0-a), - 0.0, - 1.0 - ); + fragColor = vec4(0.0, 1.0 - min(1.0, 1.0 - a), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/40_fmax.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/40_fmax.frag index 621d56ae0ca4d..1b5c8d18533c8 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/40_fmax.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/40_fmax.frag @@ -11,10 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - max(a, 0.5), - 0.0, - 1.0); + fragColor = vec4(0.0, max(a, 0.5), 0.0, 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/43_fclamp.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/43_fclamp.frag index 62674d91d0e62..0ba699b8ce0dc 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/43_fclamp.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/43_fclamp.frag @@ -12,11 +12,5 @@ layout(location = 0) uniform float a; // clamp(x, a, b) is equivalent to min(max(x, a), b) void main() { - fragColor = vec4( - 0.0, - clamp(10.0, 0.0, a), - 0.0, - clamp(-1.0, a, 10.0) - ); + fragColor = vec4(0.0, clamp(10.0, 0.0, a), 0.0, clamp(-1.0, a, 10.0)); } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/46_fmix.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/46_fmix.frag index 2176d0126da94..0ef7d6da390e4 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/46_fmix.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/46_fmix.frag @@ -11,10 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - mix(0.0, 1.0, a), - 0.0, - mix(1.0, 0.0, 1.0 - a)); + fragColor = vec4(0.0, mix(0.0, 1.0, a), 0.0, mix(1.0, 0.0, 1.0 - a)); } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/48_step.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/48_step.frag index 2a550e664cfae..79d6ab30e4c78 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/48_step.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/48_step.frag @@ -10,12 +10,8 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; -// 0.0 is returned if x (second param) < edge (first param), and 1.0 is returned otherwise. +// 0.0 is returned if x (second param) < edge (first param), and 1.0 is returned +// otherwise. void main() { - fragColor = vec4( - 0.0, - step(0.5, a), - 0.0, - 1.0 - ); + fragColor = vec4(0.0, step(0.5, a), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/49_smoothstep.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/49_smoothstep.frag index 2863ed92a8838..ae3fc5f3d8e2a 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/49_smoothstep.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/49_smoothstep.frag @@ -17,12 +17,9 @@ layout(location = 0) uniform float a; // return t * t * (3.0 - 2.0 * t); // } void main() { - fragColor = vec4( - // smoothstep(1.0, 5.0, 3.0) is 0.5, subtract to get 0.0 - smoothstep(a, 5.0, 3.0) - 0.5, - // smoothstep(0.0, 2.0, 1.0) is 0.5, add 0.5 to get 1.0 - smoothstep(0.0, 2.0, a) + 0.5, - 0.0, - 1.0 - ); + fragColor = vec4( + // smoothstep(1.0, 5.0, 3.0) is 0.5, subtract to get 0.0 + smoothstep(a, 5.0, 3.0) - 0.5, + // smoothstep(0.0, 2.0, 1.0) is 0.5, add 0.5 to get 1.0 + smoothstep(0.0, 2.0, a) + 0.5, 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/4_abs.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/4_abs.frag index 0a6fc2c8facd0..bbce4808ab35c 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/4_abs.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/4_abs.frag @@ -11,10 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - abs(-a), - 0.0, - 1.0 - ); + fragColor = vec4(0.0, abs(-a), 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/66_length.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/66_length.frag index bbd56ad93025c..4fffc6e36db3b 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/66_length.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/66_length.frag @@ -11,13 +11,12 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // length of a zero vector is 0.0 - length(vec3(a - 1.0, 0.0, 0.0)), - // sqrt(3.0^2.0 + 4.0^2.0) - 4.0 = 5.0 - 4.0 = 1.0 - length(vec2(a * 3.0, 4.0)) - 4.0, - 0.0, - // sqrt(4.0^2.0 + (-4.0)^2.0 + (-4.0)^2.0) + 4.0^2.0) - 7.0 = sqrt(16.0 + 16.0 + 16.0 + 16.0) - 7.0 = sqrt(64.0) - 7.0 = 8.0 - 7.0 = 1.0 - length(vec4(a * 4.0, -4.0, -4.0, 4.0)) - 7.0 - ); + fragColor = vec4( + // length of a zero vector is 0.0 + length(vec3(a - 1.0, 0.0, 0.0)), + // sqrt(3.0^2.0 + 4.0^2.0) - 4.0 = 5.0 - 4.0 = 1.0 + length(vec2(a * 3.0, 4.0)) - 4.0, 0.0, + // sqrt(4.0^2.0 + (-4.0)^2.0 + (-4.0)^2.0) + 4.0^2.0) - 7.0 = sqrt(16.0 + // + 16.0 + 16.0 + 16.0) - 7.0 = sqrt(64.0) - 7.0 = 8.0 - 7.0 = 1.0 + length(vec4(a * 4.0, -4.0, -4.0, 4.0)) - 7.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/67_distance.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/67_distance.frag index f0dfa2d7656d8..17330493bec92 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/67_distance.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/67_distance.frag @@ -11,13 +11,11 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // distance between same value is 0.0 - distance(a * 7.0, 7.0), - // 7.0 - 6.0 = 1.0 - distance(a * 7.0, 6.0), - 0.0, - // sqrt(7.0 * 7.0 - 6.0 * 8.0) = sqrt(49.0 - 48.0) = sqrt(1.0) = 1.0 - distance(vec2(a * 7.0, 6.0), vec2(7.0, 8.0)) - ); + fragColor = vec4( + // distance between same value is 0.0 + distance(a * 7.0, 7.0), + // 7.0 - 6.0 = 1.0 + distance(a * 7.0, 6.0), 0.0, + // sqrt(7.0 * 7.0 - 6.0 * 8.0) = sqrt(49.0 - 48.0) = sqrt(1.0) = 1.0 + distance(vec2(a * 7.0, 6.0), vec2(7.0, 8.0))); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/68_cross.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/68_cross.frag index d3ddabbe4c9bd..855fb9f1d5c80 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/68_cross.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/68_cross.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - /* cross product of parallel vectors is a zero vector */ - cross(vec3(a, 2.0, 3.0), vec3(2.0, 4.0, 6.0))[0], - 1.0, - // cross product of parallel vectors is a zero vector - cross(vec3(a, 2.0, 3.0), vec3(2.0, 4.0, 6.0))[2], - 1.0); + fragColor = vec4( + /* cross product of parallel vectors is a zero vector */ + cross(vec3(a, 2.0, 3.0), vec3(2.0, 4.0, 6.0))[0], 1.0, + // cross product of parallel vectors is a zero vector + cross(vec3(a, 2.0, 3.0), vec3(2.0, 4.0, 6.0))[2], 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/69_normalize.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/69_normalize.frag index 4c6dae16d54a4..f867b0145939a 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/69_normalize.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/69_normalize.frag @@ -11,12 +11,10 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - // normalized result is x = [3/5, 4/5], so add 2/5 to x1 to make 1.0 - normalize(vec2(a * 3.0, 4.0))[0] + 0.4, - 0.0, - // normalized result is x = [3/5, 4/5], so add 1/5 to x2 to make 1.0 - normalize(vec2(a * 3.0, 4.0))[1] + 0.2 - ); + fragColor = + vec4(0.0, + // normalized result is x = [3/5, 4/5], so add 2/5 to x1 to make 1.0 + normalize(vec2(a * 3.0, 4.0))[0] + 0.4, 0.0, + // normalized result is x = [3/5, 4/5], so add 1/5 to x2 to make 1.0 + normalize(vec2(a * 3.0, 4.0))[1] + 0.2); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/6_sign.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/6_sign.frag index 491b85deb7514..67aa487e8becc 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/6_sign.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/6_sign.frag @@ -11,13 +11,11 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - // sign is negative which results to -1.0, and -1.0 + 1.0 is 0.0 - sign(-72.45) + a, - // sign is negative which results to -1.0, and -1.0 + 2.0 is 1.0 - sign(-12.34) + 2.0 * a, - 0.0, - // sign is positive which results to 1.0 - sign(a * 0.1234)); + fragColor = vec4( + // sign is negative which results to -1.0, and -1.0 + 1.0 is 0.0 + sign(-72.45) + a, + // sign is negative which results to -1.0, and -1.0 + 2.0 is 1.0 + sign(-12.34) + 2.0 * a, 0.0, + // sign is positive which results to 1.0 + sign(a * 0.1234)); } - diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/70_faceforward.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/70_faceforward.frag index 6f6e5ccee4b13..18bb6450ed5c6 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/70_faceforward.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/70_faceforward.frag @@ -11,14 +11,14 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - 0.0, - // dot product of incident vector (2nd param) and reference vector (3rd param) is non-negative, - // so the negated first param is returned, and its first value is 1.0. - faceforward(vec2(-a, 5.0), vec2(1.0, 2.0), vec2(3.0, 4.0))[0], - 0.0, - // dot product of incident vector (2nd param) and reference vector (3rd param) is negative, - // so the original first param is returned, and its second value is 5.0, so subtract 4.0 to get 1.0. - faceforward(vec2(a, 5.0), vec2(1.0, -2.0), vec2(3.0, 4.0))[1] - 4.0 - ); + fragColor = + vec4(0.0, + // dot product of incident vector (2nd param) and reference vector + // (3rd param) is non-negative, so the negated first param is + // returned, and its first value is 1.0. + faceforward(vec2(-a, 5.0), vec2(1.0, 2.0), vec2(3.0, 4.0))[0], 0.0, + // dot product of incident vector (2nd param) and reference vector + // (3rd param) is negative, so the original first param is returned, + // and its second value is 5.0, so subtract 4.0 to get 1.0. + faceforward(vec2(a, 5.0), vec2(1.0, -2.0), vec2(3.0, 4.0))[1] - 4.0); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/8_floor.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/8_floor.frag index 900e206b6a75b..b99b963142947 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/8_floor.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/8_floor.frag @@ -11,10 +11,6 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - floor(a * 0.25), - floor(a * 1.25), - floor(a * 0.75), - floor(a * 1.75) - ); + fragColor = + vec4(floor(a * 0.25), floor(a * 1.25), floor(a * 0.75), floor(a * 1.75)); } diff --git a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/9_ceil.frag b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/9_ceil.frag index c9039aa3e0309..6aebcf6afc027 100644 --- a/lib/ui/fixtures/shaders/supported_glsl_op_shaders/9_ceil.frag +++ b/lib/ui/fixtures/shaders/supported_glsl_op_shaders/9_ceil.frag @@ -11,11 +11,6 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4( - ceil(a * -0.25), - ceil(a * 0.25), - ceil(a * -0.75), - ceil(a * 0.75) - ); + fragColor = + vec4(ceil(a * -0.25), ceil(a * 0.25), ceil(a * -0.75), ceil(a * 0.75)); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/127_OpFNegate.frag b/lib/ui/fixtures/shaders/supported_op_shaders/127_OpFNegate.frag index 9548e6862e97a..ab5fe191a2b20 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/127_OpFNegate.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/127_OpFNegate.frag @@ -11,6 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4(0.0, -(0.0-a), 0.0, 1.0); + fragColor = vec4(0.0, -(0.0 - a), 0.0, 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/129_OpFAdd.frag b/lib/ui/fixtures/shaders/supported_op_shaders/129_OpFAdd.frag index f82ccc9c26831..59feb69545b99 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/129_OpFAdd.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/129_OpFAdd.frag @@ -11,6 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4(0.0, 0.5 * a + 0.5, 0.0, 1.0); + fragColor = vec4(0.0, 0.5 * a + 0.5, 0.0, 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/131_OpFSub.frag b/lib/ui/fixtures/shaders/supported_op_shaders/131_OpFSub.frag index 2eef92f4d7b27..4fe6d354e9305 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/131_OpFSub.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/131_OpFSub.frag @@ -11,6 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4(0.0, 2.0 - a, 0.0, 1.0); + fragColor = vec4(0.0, 2.0 - a, 0.0, 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/142_OpVectorTimesScalar.frag b/lib/ui/fixtures/shaders/supported_op_shaders/142_OpVectorTimesScalar.frag index ccde0f99120bd..e34ebc3e4b9ba 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/142_OpVectorTimesScalar.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/142_OpVectorTimesScalar.frag @@ -11,6 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4(0.0, 1.0, 0.0, 1.0) * a; + fragColor = vec4(0.0, 1.0, 0.0, 1.0) * a; } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/143_OpMatrixTimesScalar.frag b/lib/ui/fixtures/shaders/supported_op_shaders/143_OpMatrixTimesScalar.frag index aab64dea92736..e86759316b1d5 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/143_OpMatrixTimesScalar.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/143_OpMatrixTimesScalar.frag @@ -11,8 +11,7 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - mat4 m = mat4(1.0); - m *= a; - fragColor = vec4(0.0, 1.0, 0.0, 1.0) * m; + mat4 m = mat4(1.0); + m *= a; + fragColor = vec4(0.0, 1.0, 0.0, 1.0) * m; } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/144_OpVectorTimesMatrix.frag b/lib/ui/fixtures/shaders/supported_op_shaders/144_OpVectorTimesMatrix.frag index b9a9ccb4bd69b..7ccea1d73124e 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/144_OpVectorTimesMatrix.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/144_OpVectorTimesMatrix.frag @@ -11,6 +11,6 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - mat4 identity = mat4(a); - fragColor = vec4(0.0, 1.0, 0.0, 1.0) * identity; + mat4 identity = mat4(a); + fragColor = vec4(0.0, 1.0, 0.0, 1.0) * identity; } diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/145_OpMatrixTimesVector.frag b/lib/ui/fixtures/shaders/supported_op_shaders/145_OpMatrixTimesVector.frag index 67365c49284ed..a26e3cd2ef40e 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/145_OpMatrixTimesVector.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/145_OpMatrixTimesVector.frag @@ -11,7 +11,6 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - mat4 identity = mat4(a); - fragColor = identity * vec4(0.0, 1.0, 0.0, 1.0); + mat4 identity = mat4(a); + fragColor = identity * vec4(0.0, 1.0, 0.0, 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/146_OpMatrixTimesMatrix.frag b/lib/ui/fixtures/shaders/supported_op_shaders/146_OpMatrixTimesMatrix.frag index 2536d21b9f030..25b13b7b06bfd 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/146_OpMatrixTimesMatrix.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/146_OpMatrixTimesMatrix.frag @@ -11,7 +11,6 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - mat4 m = mat4(1.0) * mat4(a); - fragColor = vec4(0.0, 1.0, 0.0, 1.0) * m; + mat4 m = mat4(1.0) * mat4(a); + fragColor = vec4(0.0, 1.0, 0.0, 1.0) * m; } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/148_OpDot.frag b/lib/ui/fixtures/shaders/supported_op_shaders/148_OpDot.frag index cc755d0a232fa..3f70cfdf6874d 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/148_OpDot.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/148_OpDot.frag @@ -11,6 +11,6 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - float one = dot(vec2(1.0), vec2(0.0, a)); - fragColor = vec4(0.0, one, 0.0, 1.0); + float one = dot(vec2(1.0), vec2(0.0, a)); + fragColor = vec4(0.0, one, 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/164_OpLogicalEqual.frag b/lib/ui/fixtures/shaders/supported_op_shaders/164_OpLogicalEqual.frag index de93798337eb9..cad38b470b49d 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/164_OpLogicalEqual.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/164_OpLogicalEqual.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/165_OpLogicalNotEqual.frag b/lib/ui/fixtures/shaders/supported_op_shaders/165_OpLogicalNotEqual.frag index 803bd12470af5..a720efa4971c6 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/165_OpLogicalNotEqual.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/165_OpLogicalNotEqual.frag @@ -17,5 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/166_OpLogicalOr.frag b/lib/ui/fixtures/shaders/supported_op_shaders/166_OpLogicalOr.frag index 4b31d391d5525..2e39a3a51189d 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/166_OpLogicalOr.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/166_OpLogicalOr.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/167_OpLogicalAnd.frag b/lib/ui/fixtures/shaders/supported_op_shaders/167_OpLogicalAnd.frag index 55e7fd2eb032c..585ddec718fe4 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/167_OpLogicalAnd.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/167_OpLogicalAnd.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/168_OpLogicalNot.frag b/lib/ui/fixtures/shaders/supported_op_shaders/168_OpLogicalNot.frag index bec1109483b64..b74575a8a22a5 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/168_OpLogicalNot.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/168_OpLogicalNot.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/180_OpFOrdEqual.frag b/lib/ui/fixtures/shaders/supported_op_shaders/180_OpFOrdEqual.frag index 480080eb06f79..901ab522d1707 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/180_OpFOrdEqual.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/180_OpFOrdEqual.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/183_OpFUnordNotEqual.frag b/lib/ui/fixtures/shaders/supported_op_shaders/183_OpFUnordNotEqual.frag index b49ff5986dca2..259cfb1b2c4bb 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/183_OpFUnordNotEqual.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/183_OpFUnordNotEqual.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/184_OpFOrdLessThan.frag b/lib/ui/fixtures/shaders/supported_op_shaders/184_OpFOrdLessThan.frag index 69992de3d1d0f..4e823f77414dd 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/184_OpFOrdLessThan.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/184_OpFOrdLessThan.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 1.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/186_OpFOrdGreaterThan.frag b/lib/ui/fixtures/shaders/supported_op_shaders/186_OpFOrdGreaterThan.frag index 26e9753a63c9f..1a4980522946a 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/186_OpFOrdGreaterThan.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/186_OpFOrdGreaterThan.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/188_OpFOrdLessThanEqual.frag b/lib/ui/fixtures/shaders/supported_op_shaders/188_OpFOrdLessThanEqual.frag index f0dcc0f281bcd..674acef7253f5 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/188_OpFOrdLessThanEqual.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/188_OpFOrdLessThanEqual.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/190_OpFOrdGreaterThanEqual.frag b/lib/ui/fixtures/shaders/supported_op_shaders/190_OpFOrdGreaterThanEqual.frag index 0523b2e298668..8cb2a90040552 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/190_OpFOrdGreaterThanEqual.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/190_OpFOrdGreaterThanEqual.frag @@ -17,4 +17,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/19_OpTypeVoid.frag b/lib/ui/fixtures/shaders/supported_op_shaders/19_OpTypeVoid.frag index a221a4f8c2b94..a89fe54cf147e 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/19_OpTypeVoid.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/19_OpTypeVoid.frag @@ -11,5 +11,5 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - fragColor = vec4(0.0, a, 0.0, 1.0); + fragColor = vec4(0.0, a, 0.0, 1.0); } diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/20_OpTypeBool.frag b/lib/ui/fixtures/shaders/supported_op_shaders/20_OpTypeBool.frag index ce1ef4c3cd26c..1fd9a6a215217 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/20_OpTypeBool.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/20_OpTypeBool.frag @@ -11,10 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - bool f = false; - bool t = bool(a); - float zero = float(f); - float one = float(t); - fragColor = vec4(zero, one, zero, one); + bool f = false; + bool t = bool(a); + float zero = float(f); + float one = float(t); + fragColor = vec4(zero, one, zero, one); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/21_OpTypeInt.frag b/lib/ui/fixtures/shaders/supported_op_shaders/21_OpTypeInt.frag index 39b6b48ff2e73..f9bbc90766f6a 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/21_OpTypeInt.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/21_OpTypeInt.frag @@ -11,10 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - int zeroInt = 0; - int oneInt = int(a); - float zero = float(zeroInt); - float one = float(oneInt); - fragColor = vec4(zero, one, zero, one); + int zeroInt = 0; + int oneInt = int(a); + float zero = float(zeroInt); + float one = float(oneInt); + fragColor = vec4(zero, one, zero, one); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/22_OpTypeFloat.frag b/lib/ui/fixtures/shaders/supported_op_shaders/22_OpTypeFloat.frag index ffc779c0ff737..5440a18ed8437 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/22_OpTypeFloat.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/22_OpTypeFloat.frag @@ -11,7 +11,6 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - float zero = 0.0; - fragColor = vec4(zero, a, zero, a); + float zero = 0.0; + fragColor = vec4(zero, a, zero, a); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/23_OpTypeVector.frag b/lib/ui/fixtures/shaders/supported_op_shaders/23_OpTypeVector.frag index 9137ccdb20564..57de83c8b6a6a 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/23_OpTypeVector.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/23_OpTypeVector.frag @@ -11,7 +11,7 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - vec2 ones = vec2(a); - vec3 zeros = vec3(0.0, 0.0, 0.0); - fragColor = vec4(zeros[0], ones[0], zeros[2], ones[1]); + vec2 ones = vec2(a); + vec3 zeros = vec3(0.0, 0.0, 0.0); + fragColor = vec4(zeros[0], ones[0], zeros[2], ones[1]); } diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/246_OpLoopMerge.frag b/lib/ui/fixtures/shaders/supported_op_shaders/246_OpLoopMerge.frag index 11c7d2a230f31..6a48ad4abedb6 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/246_OpLoopMerge.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/246_OpLoopMerge.frag @@ -25,4 +25,3 @@ void main() { } fragColor = vec4(0.0, sum, 0.0, 1.0); } - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/24_OpTypeMatrix.frag b/lib/ui/fixtures/shaders/supported_op_shaders/24_OpTypeMatrix.frag index 8b2032d99360e..da2564f6c55ff 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/24_OpTypeMatrix.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/24_OpTypeMatrix.frag @@ -11,12 +11,9 @@ layout(location = 0) out vec4 fragColor; layout(location = 0) uniform float a; void main() { - mat2 zeros = mat2(0.0); - mat3 ones = mat3(a); - mat4 identity = mat4( - a, 0.0, 0.0, 0.0, - 0.0, a, 0.0, 0.0, - 0.0, 0.0, a, 0.0, - 0.0, 0.0, 0.0, a); - fragColor = vec4(zeros[1][1], ones[2][2], identity[3][1], identity[3][3]); + mat2 zeros = mat2(0.0); + mat3 ones = mat3(a); + mat4 identity = mat4(a, 0.0, 0.0, 0.0, 0.0, a, 0.0, 0.0, 0.0, 0.0, a, 0.0, + 0.0, 0.0, 0.0, a); + fragColor = vec4(zeros[1][1], ones[2][2], identity[3][1], identity[3][3]); } diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/250_OpBranchConditional.frag b/lib/ui/fixtures/shaders/supported_op_shaders/250_OpBranchConditional.frag index c72ea85af02bb..8b2e77dfccbc7 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/250_OpBranchConditional.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/250_OpBranchConditional.frag @@ -20,5 +20,3 @@ void main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - - diff --git a/lib/ui/fixtures/shaders/supported_op_shaders/33_OpTypeFunction.frag b/lib/ui/fixtures/shaders/supported_op_shaders/33_OpTypeFunction.frag index eb468e82aa0d1..b9db34335a0be 100644 --- a/lib/ui/fixtures/shaders/supported_op_shaders/33_OpTypeFunction.frag +++ b/lib/ui/fixtures/shaders/supported_op_shaders/33_OpTypeFunction.frag @@ -19,6 +19,5 @@ float one() { } void main() { - fragColor = vec4(zero(), one(), zero(), one()); + fragColor = vec4(zero(), one(), zero(), one()); } - diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 307ac9ca7affa..891a18923b9f5 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4245,7 +4245,7 @@ class FragmentProgram extends NativeFieldWrapperClass1 { /// [FragmentProgram.fragmentShader] method. The float uniforms list is /// initialized to the size expected by the shader and is zero-filled. Uniforms /// of float type can then be set by calling [setFloat]. Sampler uniforms are -/// set by calling [setSampler]. +/// set by calling [setImageSampler]. /// /// A [FragmentShader] can be re-used, and this is an efficient way to avoid /// allocating and re-initializing the uniform buffer and samplers. However, @@ -4288,7 +4288,7 @@ class FragmentShader extends Shader { /// is: /// /// ```dart - /// void updateShader(ui.FragmentShader shader, Color color, ImageShader sampler) { + /// void updateShader(ui.FragmentShader shader, Color color, ui.Image image) { /// shader.setFloat(0, 23); // uScale /// shader.setFloat(1, 114); // uMagnitude x /// shader.setFloat(2, 83); // uMagnitude y @@ -4300,12 +4300,12 @@ class FragmentShader extends Shader { /// shader.setFloat(6, color.opacity); // uColor a /// /// // initialize sampler uniform. - /// shader.setSampler(0, sampler); + /// shader.setImageSampler(0, image); /// } /// ``` /// /// Note how the indexes used does not count the `sampler2D` uniform. This - /// uniform will be set separately with [setSampler], with the index starting + /// uniform will be set separately with [setImageSampler], with the index starting /// over at 0. /// /// Any float uniforms that are left uninitialized will default to `0`. @@ -4314,16 +4314,16 @@ class FragmentShader extends Shader { _floats[index] = value; } - /// Sets the sampler uniform at [index] to [sampler]. + /// Sets the sampler uniform at [index] to [image]. /// - /// The index provided to setSampler is the index of the sampler uniform defined + /// The index provided to setImageSampler is the index of the sampler uniform defined /// in the fragment program, excluding all non-sampler uniforms. /// /// All the sampler uniforms that a shader expects must be provided or the /// results will be undefined. - void setSampler(int index, ImageShader sampler) { + void setImageSampler(int index, Image image) { assert(!debugDisposed, 'Tried to access uniforms on a disposed Shader: $this'); - _setSampler(index, sampler); + _setImageSampler(index, image._image); } /// Releases the native resources held by the [FragmentShader]. @@ -4341,8 +4341,8 @@ class FragmentShader extends Shader { @FfiNative('ReusableFragmentShader::Create') external Float32List _constructor(FragmentProgram program, int floatUniforms, int samplerUniforms); - @FfiNative, Handle, Handle)>('ReusableFragmentShader::SetSampler') - external void _setSampler(int index, ImageShader sampler); + @FfiNative, Handle, Handle)>('ReusableFragmentShader::SetImageSampler') + external void _setImageSampler(int index, _Image sampler); @FfiNative)>('ReusableFragmentShader::ValidateSamplers') external bool _validateSamplers(); diff --git a/lib/ui/painting/fragment_shader.cc b/lib/ui/painting/fragment_shader.cc index 38f62ef3d507e..0a153a0f008cc 100644 --- a/lib/ui/painting/fragment_shader.cc +++ b/lib/ui/painting/fragment_shader.cc @@ -7,6 +7,8 @@ #include "flutter/lib/ui/painting/fragment_shader.h" +#include "flutter/display_list/display_list_color_source.h" +#include "flutter/display_list/display_list_tile_mode.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/fragment_program.h" #include "flutter/lib/ui/ui_dart_state.h" @@ -61,27 +63,25 @@ bool ReusableFragmentShader::ValidateSamplers() { return true; } -void ReusableFragmentShader::SetSampler(Dart_Handle index_handle, - Dart_Handle sampler_handle) { +void ReusableFragmentShader::SetImageSampler(Dart_Handle index_handle, + Dart_Handle image_handle) { uint64_t index = tonic::DartConverter::FromDart(index_handle); - ImageShader* sampler = - tonic::DartConverter::FromDart(sampler_handle); + CanvasImage* image = + tonic::DartConverter::FromDart(image_handle); if (index >= samplers_.size()) { Dart_ThrowException(tonic::ToDart("Sampler index out of bounds")); } - // ImageShaders can hold a preferred value for sampling options and - // developers are encouraged to use that value or the value will be supplied - // by "the environment where it is used". The environment here does not - // contain a value to be used if the developer did not specify a preference - // when they constructed the ImageShader, so we will use kNearest which is - // the default filterQuality in a Paint object. - DlImageSampling sampling = DlImageSampling::kNearestNeighbor; + // TODO(115794): Once the DlImageSampling enum is replaced, expose the + // sampling options as a new default parameter for users. + samplers_[index] = std::make_shared( + image->image(), DlTileMode::kClamp, DlTileMode::kClamp, + DlImageSampling::kNearestNeighbor, nullptr); + auto* uniform_floats = reinterpret_cast(uniform_data_->writable_data()); - samplers_[index] = sampler->shader(sampling); - uniform_floats[float_count_ + 2 * index] = sampler->width(); - uniform_floats[float_count_ + 2 * index + 1] = sampler->height(); + uniform_floats[float_count_ + 2 * index] = image->width(); + uniform_floats[float_count_ + 2 * index + 1] = image->height(); } std::shared_ptr ReusableFragmentShader::shader( diff --git a/lib/ui/painting/fragment_shader.h b/lib/ui/painting/fragment_shader.h index 5b948e80dea0c..e6756b09edd30 100644 --- a/lib/ui/painting/fragment_shader.h +++ b/lib/ui/painting/fragment_shader.h @@ -34,7 +34,7 @@ class ReusableFragmentShader : public Shader { Dart_Handle float_count, Dart_Handle sampler_count); - void SetSampler(Dart_Handle index, Dart_Handle sampler); + void SetImageSampler(Dart_Handle index, Dart_Handle image); bool ValidateSamplers(); diff --git a/lib/ui/painting/multi_frame_codec.cc b/lib/ui/painting/multi_frame_codec.cc index 3099a618b8c61..76af13ba161fa 100644 --- a/lib/ui/painting/multi_frame_codec.cc +++ b/lib/ui/painting/multi_frame_codec.cc @@ -93,7 +93,11 @@ sk_sp MultiFrameCodec::State::GetNextFrameImage( SkImageInfo updated = info.makeAlphaType(kPremul_SkAlphaType); info = updated; } - bitmap.allocPixels(info); + if (!bitmap.tryAllocPixels(info)) { + FML_LOG(ERROR) << "Failed to allocate memory for bitmap of size " + << info.computeMinByteSize() << "B"; + return nullptr; + } ImageGenerator::FrameInfo frameInfo = generator_->GetFrameInfo(nextFrameIndex_); diff --git a/lib/web_ui/README.md b/lib/web_ui/README.md index e5766b8685a60..057ec0874f1ca 100644 --- a/lib/web_ui/README.md +++ b/lib/web_ui/README.md @@ -339,3 +339,7 @@ Once you know the version for the Emscripten SDK, change the line in [4]: https://chrome-infra-packages.appspot.com/p/flutter_internal [5]: https://cs.opensource.google/flutter/recipes/+/master:recipes/engine/web_engine.py [6]: https://chromium.googlesource.com/chromium/src.git/+/main/docs/cipd_and_3pp.md#What-is-CIPD + +## Unicode properties + +We pull the unicode properties we need from `third_party/web_unicode`. See `third_party/web_unicode/README.md` for more details on how we generate Dart code from unicode properties. diff --git a/lib/web_ui/dev/licenses.dart b/lib/web_ui/dev/licenses.dart index 7048576c62499..21383493479a2 100644 --- a/lib/web_ui/dev/licenses.dart +++ b/lib/web_ui/dev/licenses.dart @@ -35,7 +35,6 @@ class LicensesCommand extends Command { 'lib', 'test', 'dev', - 'tool' ]) { final String expectedAbsoluteDirectory = path.join(environment.webUiRootDir.path, expectedDirectory); diff --git a/lib/web_ui/lib/compositing.dart b/lib/web_ui/lib/compositing.dart index 11154ad6608e9..d3f0acddd6797 100644 --- a/lib/web_ui/lib/compositing.dart +++ b/lib/web_ui/lib/compositing.dart @@ -71,6 +71,7 @@ abstract class SceneBuilder { }); ImageFilterEngineLayer pushImageFilter( ImageFilter filter, { + Offset offset = Offset.zero, ImageFilterEngineLayer? oldLayer, }); BackdropFilterEngineLayer pushBackdropFilter( diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 7a0d7439cb8ff..0d602c10fc3b4 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -818,7 +818,7 @@ abstract class FragmentProgram { abstract class FragmentShader implements Shader { void setFloat(int index, double value); - void setSampler(int index, ImageShader sampler); + void setImageSampler(int index, Image image); @override void dispose(); diff --git a/lib/web_ui/lib/src/engine/assets.dart b/lib/web_ui/lib/src/engine/assets.dart index 0fdb7006072a3..bfc7bba0e46e9 100644 --- a/lib/web_ui/lib/src/engine/assets.dart +++ b/lib/web_ui/lib/src/engine/assets.dart @@ -84,7 +84,7 @@ class AssetManager { printWarning('Asset manifest does not exist at `$url` – ignoring.'); return Uint8List.fromList(utf8.encode('{}')).buffer.asByteData(); } - throw AssetManagerException(url, request.status!); + throw AssetManagerException(url, request.status!.toInt()); } final String? constructorName = target == null ? 'null' : diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart index 769b2812f512b..3ff3c714e0907 100644 --- a/lib/web_ui/lib/src/engine/browser_detection.dart +++ b/lib/web_ui/lib/src/engine/browser_detection.dart @@ -142,7 +142,7 @@ OperatingSystem detectOperatingSystem({ // iDevices requesting a "desktop site" spoof their UA so it looks like a Mac. // This checks if we're in a touch device, or on a real mac. final int maxTouchPoints = - overrideMaxTouchPoints ?? domWindow.navigator.maxTouchPoints ?? 0; + overrideMaxTouchPoints ?? domWindow.navigator.maxTouchPoints?.toInt() ?? 0; if (maxTouchPoints > 2) { return OperatingSystem.iOs; } diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvas.dart b/lib/web_ui/lib/src/engine/canvaskit/canvas.dart index 63661de2a0455..e3c358e45f044 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvas.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvas.dart @@ -37,7 +37,7 @@ class CkCanvas { final SkCanvas skCanvas; - int? get saveCount => skCanvas.getSaveCount(); + int? get saveCount => skCanvas.getSaveCount().toInt(); void clear(ui.Color color) { skCanvas.clear(toSharedSkColor1(color)); @@ -274,7 +274,7 @@ class CkCanvas { } int save() { - return skCanvas.save(); + return skCanvas.save().toInt(); } void saveLayer(ui.Rect bounds, CkPaint? paint) { diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart index dc35f568d231c..25e5f79e83874 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -96,10 +96,10 @@ extension CanvasKitExtension on CanvasKit { ); // Text decoration enum is embedded in the CanvasKit object itself. - external int get NoDecoration; - external int get UnderlineDecoration; - external int get OverlineDecoration; - external int get LineThroughDecoration; + external double get NoDecoration; + external double get UnderlineDecoration; + external double get OverlineDecoration; + external double get LineThroughDecoration; // End of text decoration enum. external SkTextDecorationStyleEnum get DecorationStyle; @@ -109,7 +109,7 @@ extension CanvasKitExtension on CanvasKit { external SkFontMgrNamespace get FontMgr; external TypefaceFontProviderNamespace get TypefaceFontProvider; external SkTypefaceFactory get Typeface; - external int GetWebGLContext( + external double GetWebGLContext( DomCanvasElement canvas, SkWebGLContextOptions options); external SkGrContext MakeGrContext(int glContext); external SkSurface? MakeOnScreenGLSurface( @@ -195,8 +195,8 @@ class SkSurface {} extension SkSurfaceExtension on SkSurface { external SkCanvas getCanvas(); external void flush(); - external int width(); - external int height(); + external double width(); + external double height(); external void dispose(); external SkImage makeImageSnapshot(); } @@ -226,7 +226,7 @@ extension SkFontSlantEnumExtension on SkFontSlantEnum { class SkFontSlant {} extension SkFontSlantExtension on SkFontSlant { - external int get value; + external double get value; } final List _skFontSlants = [ @@ -260,7 +260,7 @@ extension SkFontWeightEnumExtension on SkFontWeightEnum { class SkFontWeight {} extension SkFontWeightExtension on SkFontWeight { - external int get value; + external double get value; } final List _skFontWeights = [ @@ -293,7 +293,7 @@ extension SkAffinityEnumExtension on SkAffinityEnum { class SkAffinity {} extension SkAffinityExtension on SkAffinity { - external int get value; + external double get value; } final List _skAffinitys = [ @@ -319,7 +319,7 @@ extension SkTextDirectionEnumExtension on SkTextDirectionEnum { class SkTextDirection {} extension SkTextDirectionExtension on SkTextDirection { - external int get value; + external double get value; } // Flutter enumerates text directions as RTL, LTR, while CanvasKit @@ -351,7 +351,7 @@ extension SkTextAlignEnumExtension on SkTextAlignEnum { class SkTextAlign {} extension SkTextAlignExtension on SkTextAlign { - external int get value; + external double get value; } final List _skTextAligns = [ @@ -383,7 +383,7 @@ extension SkTextHeightBehaviorEnumExtension on SkTextHeightBehaviorEnum { class SkTextHeightBehavior {} extension SkTextHeightBehaviorExtension on SkTextHeightBehavior { - external int get value; + external double get value; } final List _skTextHeightBehaviors = @@ -418,7 +418,7 @@ extension SkRectHeightStyleEnumExtension on SkRectHeightStyleEnum { class SkRectHeightStyle {} extension SkRectHeightStyleExtension on SkRectHeightStyle { - external int get value; + external double get value; } final List _skRectHeightStyles = [ @@ -448,7 +448,7 @@ extension SkRectWidthStyleEnumExtension on SkRectWidthStyleEnum { class SkRectWidthStyle {} extension SkRectWidthStyleExtension on SkRectWidthStyle { - external int get value; + external double get value; } final List _skRectWidthStyles = [ @@ -476,7 +476,7 @@ extension SkVertexModeEnumExtension on SkVertexModeEnum { class SkVertexMode {} extension SkVertexModeExtension on SkVertexMode { - external int get value; + external double get value; } final List _skVertexModes = [ @@ -504,7 +504,7 @@ extension SkPointModeEnumExtension on SkPointModeEnum { class SkPointMode {} extension SkPointModeExtension on SkPointMode { - external int get value; + external double get value; } final List _skPointModes = [ @@ -531,7 +531,7 @@ extension SkClipOpEnumExtension on SkClipOpEnum { class SkClipOp {} extension SkClipOpExtension on SkClipOp { - external int get value; + external double get value; } final List _skClipOps = [ @@ -557,7 +557,7 @@ extension SkFillTypeEnumExtension on SkFillTypeEnum { class SkFillType {} extension SkFillTypeExtension on SkFillType { - external int get value; + external double get value; } final List _skFillTypes = [ @@ -586,7 +586,7 @@ extension SkPathOpEnumExtension on SkPathOpEnum { class SkPathOp {} extension SkPathOpExtension on SkPathOp { - external int get value; + external double get value; } final List _skPathOps = [ @@ -617,7 +617,7 @@ extension SkBlurStyleEnumExtension on SkBlurStyleEnum { class SkBlurStyle {} extension SkBlurStyleExtension on SkBlurStyle { - external int get value; + external double get value; } final List _skBlurStyles = [ @@ -646,7 +646,7 @@ extension SkStrokeCapEnumExtension on SkStrokeCapEnum { class SkStrokeCap {} extension SkStrokeCapExtension on SkStrokeCap { - external int get value; + external double get value; } final List _skStrokeCaps = [ @@ -673,7 +673,7 @@ extension SkPaintStyleEnumExtension on SkPaintStyleEnum { class SkPaintStyle {} extension SkPaintStyleExtension on SkPaintStyle { - external int get value; + external double get value; } final List _skPaintStyles = [ @@ -726,7 +726,7 @@ extension SkBlendModeEnumExtension on SkBlendModeEnum { class SkBlendMode {} extension SkBlendModeExtension on SkBlendMode { - external int get value; + external double get value; } final List _skBlendModes = [ @@ -780,7 +780,7 @@ extension SkStrokeJoinEnumExtension on SkStrokeJoinEnum { class SkStrokeJoin {} extension SkStrokeJoinExtension on SkStrokeJoin { - external int get value; + external double get value; } final List _skStrokeJoins = [ @@ -809,7 +809,7 @@ extension SkTileModeEnumExtension on SkTileModeEnum { class SkTileMode {} extension SkTileModeExtension on SkTileMode { - external int get value; + external double get value; } final List _skTileModes = [ @@ -837,7 +837,7 @@ extension SkFilterModeEnumExtension on SkFilterModeEnum { class SkFilterMode {} extension SkFilterModeExtension on SkFilterMode { - external int get value; + external double get value; } SkFilterMode toSkFilterMode(ui.FilterQuality filterQuality) { @@ -861,7 +861,7 @@ extension SkMipmapModeEnumExtension on SkMipmapModeEnum { class SkMipmapMode {} extension SkMipmapModeExtension on SkMipmapMode { - external int get value; + external double get value; } SkMipmapMode toSkMipmapMode(ui.FilterQuality filterQuality) { @@ -885,7 +885,7 @@ extension SkAlphaTypeEnumExtension on SkAlphaTypeEnum { class SkAlphaType {} extension SkAlphaTypeExtension on SkAlphaType { - external int get value; + external double get value; } @JS() @@ -911,7 +911,7 @@ extension SkColorTypeEnumExtension on SkColorTypeEnum { class SkColorType {} extension SkColorTypeExtension on SkColorType { - external int get value; + external double get value; } @JS() @@ -920,19 +920,19 @@ extension SkColorTypeExtension on SkColorType { class SkAnimatedImage {} extension SkAnimatedImageExtension on SkAnimatedImage { - external int getFrameCount(); + external double getFrameCount(); - external int getRepetitionCount(); + external double getRepetitionCount(); /// Returns duration in milliseconds. - external int currentFrameDuration(); + external double currentFrameDuration(); /// Advances to the next frame and returns its duration in milliseconds. - external int decodeNextFrame(); + external double decodeNextFrame(); external SkImage makeImageAtCurrentFrame(); - external int width(); - external int height(); + external double width(); + external double height(); /// Deletes the C++ object. /// @@ -948,8 +948,8 @@ class SkImage {} extension SkImageExtension on SkImage { external void delete(); - external int width(); - external int height(); + external double width(); + external double height(); external SkShader makeShaderCubic( SkTileMode tileModeX, SkTileMode tileModeY, @@ -1786,8 +1786,8 @@ extension SkCanvasExtension on SkCanvas { SkBlendMode blendMode, SkPaint paint, ); - external int save(); - external int getSaveCount(); + external double save(); + external double getSaveCount(); external void saveLayer( SkPaint? paint, Float32List? bounds, @@ -1902,7 +1902,7 @@ extension SkTextDecorationStyleEnumExtension on SkTextDecorationStyleEnum { class SkTextDecorationStyle {} extension SkTextDecorationStyleExtension on SkTextDecorationStyle { - external int get value; + external double get value; } final List _skTextDecorationStyles = @@ -1932,7 +1932,7 @@ extension SkTextBaselineEnumExtension on SkTextBaselineEnum { class SkTextBaseline {} extension SkTextBaselineExtension on SkTextBaseline { - external int get value; + external double get value; } final List _skTextBaselines = [ @@ -1962,7 +1962,7 @@ extension SkPlaceholderAlignmentEnumExtension on SkPlaceholderAlignmentEnum { class SkPlaceholderAlignment {} extension SkPlaceholderAlignmentExtension on SkPlaceholderAlignment { - external int get value; + external double get value; } final List _skPlaceholderAlignments = @@ -2120,10 +2120,10 @@ extension TypefaceFontProviderExtension on TypefaceFontProvider { class SkLineMetrics {} extension SkLineMetricsExtension on SkLineMetrics { - external int get startIndex; - external int get endIndex; - external int get endExcludingWhitespaces; - external int get endIncludingNewline; + external double get startIndex; + external double get endIndex; + external double get endExcludingWhitespaces; + external double get endIncludingNewline; external bool get isHardBreak; external double get ascent; external double get descent; @@ -2131,7 +2131,7 @@ extension SkLineMetricsExtension on SkLineMetrics { external double get width; external double get left; external double get baseline; - external int get lineNumber; + external double get lineNumber; } @JS() @@ -2171,7 +2171,7 @@ class SkTextPosition {} extension SkTextPositionExtnsion on SkTextPosition { external SkAffinity get affinity; - external int get pos; + external double get pos; } @JS() @@ -2179,8 +2179,8 @@ extension SkTextPositionExtnsion on SkTextPosition { class SkTextRange {} extension SkTextRangeExtension on SkTextRange { - external int get start; - external int get end; + external double get start; + external double get end; } @JS() @@ -2475,7 +2475,7 @@ void debugResetBrowserSupportsFinalizationRegistry() { class SkData {} extension SkDataExtension on SkData { - external int size(); + external double size(); external bool isEmpty(); external Uint8List bytes(); external void delete(); @@ -2498,11 +2498,11 @@ extension SkImageInfoExtension on SkImageInfo { external SkAlphaType get alphaType; external ColorSpace get colorSpace; external SkColorType get colorType; - external int get height; + external double get height; external bool get isEmpty; external bool get isOpaque; external Float32List get bounds; - external int get width; + external double get width; external SkImageInfo makeAlphaType(SkAlphaType alphaType); external SkImageInfo makeColorSpace(ColorSpace colorSpace); external SkImageInfo makeColorType(SkColorType colorType); @@ -2526,8 +2526,8 @@ extension SkPartialImageInfoExtension on SkPartialImageInfo { external SkAlphaType get alphaType; external ColorSpace get colorSpace; external SkColorType get colorType; - external int get height; - external int get width; + external double get height; + external double get width; } /// Helper interop methods for [patchCanvasKitModule]. diff --git a/lib/web_ui/lib/src/engine/canvaskit/image.dart b/lib/web_ui/lib/src/engine/canvaskit/image.dart index 88d0d9fe8dc0a..ad570e4110326 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -111,7 +111,7 @@ Future fetchImage( if (chunkCallback != null) { request.addEventListener('progress', allowInterop((DomEvent event) { event = event as DomProgressEvent; - chunkCallback.call(event.loaded!, event.total!); + chunkCallback.call(event.loaded!.toInt(), event.total!.toInt()); })); } @@ -123,7 +123,7 @@ Future fetchImage( })); request.addEventListener('load', allowInterop((DomEvent event) { - final int status = request.status!; + final int status = request.status!.toInt(); final bool accepted = status >= 200 && status < 300; final bool fileUri = status == 0; // file:// URIs have status of 0. final bool notModified = status == 304; @@ -173,8 +173,8 @@ class CkImage implements ui.Image, StackTraceDebugger { 'be able to resurrect it once it has been garbage collected.'); return; } - final int originalWidth = skImage.width(); - final int originalHeight = skImage.height(); + final int originalWidth = skImage.width().toInt(); + final int originalHeight = skImage.height().toInt(); box = SkiaObjectBox.resurrectable(this, skImage, () { final SkImage? skImage = canvasKit.MakeImage( SkImageInfo( @@ -277,13 +277,13 @@ class CkImage implements ui.Image, StackTraceDebugger { @override int get width { assert(_debugCheckIsNotDisposed()); - return skImage.width(); + return skImage.width().toInt(); } @override int get height { assert(_debugCheckIsNotDisposed()); - return skImage.height(); + return skImage.height().toInt(); } @override @@ -328,8 +328,8 @@ class CkImage implements ui.Image, StackTraceDebugger { alphaType: alphaType, colorType: colorType, colorSpace: colorSpace, - width: skImage.width(), - height: skImage.height(), + width: skImage.width().toInt(), + height: skImage.height().toInt(), ); bytes = skImage.readPixels(0, 0, imageInfo); } else { diff --git a/lib/web_ui/lib/src/engine/canvaskit/image_wasm_codecs.dart b/lib/web_ui/lib/src/engine/canvaskit/image_wasm_codecs.dart index 15a6a93834ee2..e7772d7a10cb8 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image_wasm_codecs.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image_wasm_codecs.dart @@ -45,8 +45,8 @@ class CkAnimatedImage extends ManagedSkiaObject ); } - _frameCount = animatedImage.getFrameCount(); - _repetitionCount = animatedImage.getRepetitionCount(); + _frameCount = animatedImage.getFrameCount().toInt(); + _repetitionCount = animatedImage.getRepetitionCount().toInt(); // Normally CanvasKit initializes `SkAnimatedImage` to point to the first // frame in the animation. However, if the Skia object has been deleted then @@ -116,7 +116,7 @@ class CkAnimatedImage extends ManagedSkiaObject // current Skia frame, then advance SkAnimatedImage to the next frame, and // return the current frame. final ui.FrameInfo currentFrame = AnimatedImageFrameInfo( - Duration(milliseconds: animatedImage.currentFrameDuration()), + Duration(milliseconds: animatedImage.currentFrameDuration().toInt()), CkImage(animatedImage.makeImageAtCurrentFrame()), ); diff --git a/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart b/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart index c3ffcc7719fc9..a1e348e47f342 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart @@ -179,9 +179,14 @@ class CkBrowserImageDecoder implements ui.Codec { // package:js bindings don't work with getters that return a Promise, which // is why js_util is used instead. await promiseToFuture(getJsProperty(webDecoder, 'completed')); - frameCount = webDecoder.tracks.selectedTrack!.frameCount; - repetitionCount = webDecoder.tracks.selectedTrack!.repetitionCount; - + frameCount = webDecoder.tracks.selectedTrack!.frameCount.toInt(); + + // We coerce the DOM's `repetitionCount` into an int by explicitly + // handling `infinity`. Note: This will still throw if the DOM returns a + // `NaN. + final double rawRepetitionCount = webDecoder.tracks.selectedTrack!.repetitionCount; + repetitionCount = rawRepetitionCount == double.infinity ? -1 : + rawRepetitionCount.toInt(); _cachedWebDecoder = webDecoder; // Expire the decoder if it's not used for several seconds. If the image is @@ -234,15 +239,15 @@ class CkBrowserImageDecoder implements ui.Codec { alphaType: canvasKit.AlphaType.Premul, colorType: canvasKit.ColorType.RGBA_8888, colorSpace: SkColorSpaceSRGB, - width: frame.displayWidth, - height: frame.displayHeight, + width: frame.displayWidth.toInt(), + height: frame.displayHeight.toInt(), ), ); // Duration can be null if the image is not animated. However, Flutter // requires a non-null value. 0 indicates that the frame is meant to be // displayed indefinitely, which is fine for a static image. - final Duration duration = Duration(microseconds: frame.duration ?? 0); + final Duration duration = Duration(microseconds: frame.duration?.toInt() ?? 0); if (skImage == null) { throw ImageCodecException( @@ -445,7 +450,7 @@ bool _shouldReadPixelsUnmodified(VideoFrame videoFrame, ui.ImageByteFormat forma } Future readVideoFramePixelsUnmodified(VideoFrame videoFrame) async { - final int size = videoFrame.allocationSize(); + final int size = videoFrame.allocationSize().toInt(); final Uint8List destination = Uint8List(size); final JsPromise copyPromise = videoFrame.copyTo(destination); await promiseToFuture(copyPromise); @@ -453,8 +458,8 @@ Future readVideoFramePixelsUnmodified(VideoFrame videoFrame) async { } Future encodeVideoFrameAsPng(VideoFrame videoFrame) async { - final int width = videoFrame.displayWidth; - final int height = videoFrame.displayHeight; + final int width = videoFrame.displayWidth.toInt(); + final int height = videoFrame.displayHeight.toInt(); final DomCanvasElement canvas = createDomCanvasElement(width: width, height: height); final DomCanvasRenderingContext2D ctx = canvas.context2D; diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer.dart b/lib/web_ui/lib/src/engine/canvaskit/layer.dart index fa067f049f8d3..3f09e27e0bff8 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer.dart @@ -394,18 +394,22 @@ class OffsetEngineLayer extends TransformEngineLayer /// A layer that applies an [ui.ImageFilter] to its children. class ImageFilterEngineLayer extends ContainerLayer implements ui.ImageFilterEngineLayer { - ImageFilterEngineLayer(this._filter); + ImageFilterEngineLayer(this._filter, this._offset); + final ui.Offset _offset; final ui.ImageFilter _filter; @override void paint(PaintContext paintContext) { assert(needsPainting); + paintContext.internalNodesCanvas.save(); + paintContext.internalNodesCanvas.translate(_offset.dx, _offset.dy); final CkPaint paint = CkPaint(); paint.imageFilter = _filter; paintContext.internalNodesCanvas.saveLayer(paintBounds, paint); paintChildren(paintContext); paintContext.internalNodesCanvas.restore(); + paintContext.internalNodesCanvas.restore(); } // TODO(dnfield): dispose of the _filter diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart index bca671f68026b..addd3aa5b992b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart @@ -155,9 +155,10 @@ class LayerSceneBuilder implements ui.SceneBuilder { ImageFilterEngineLayer pushImageFilter( ui.ImageFilter filter, { ui.ImageFilterEngineLayer? oldLayer, + ui.Offset offset = ui.Offset.zero, }) { assert(filter != null); - return pushLayer(ImageFilterEngineLayer(filter)); + return pushLayer(ImageFilterEngineLayer(filter, offset)); } @override diff --git a/lib/web_ui/lib/src/engine/canvaskit/painting.dart b/lib/web_ui/lib/src/engine/canvaskit/painting.dart index b9a7296207c7e..8cd9fc1ab817c 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/painting.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/painting.dart @@ -8,6 +8,7 @@ import 'dart:typed_data'; import 'package:ui/ui.dart' as ui; import '../color_filter.dart'; +import '../vector_math.dart'; import 'canvaskit_api.dart'; import 'color_filter.dart'; import 'image_filter.dart'; @@ -477,7 +478,9 @@ class CkFragmentShader implements ui.FragmentShader { } @override - void setSampler(int index, ui.ImageShader sampler) { + void setImageSampler(int index, ui.Image image) { + final ui.ImageShader sampler = ui.ImageShader(image, ui.TileMode.clamp, + ui.TileMode.clamp, toMatrix64(Matrix4.identity().storage)); samplers[index] = (sampler as CkShader).skiaObject; setFloat(lastFloatIndex + 2 * index, (sampler as CkImageShader).imageWidth.toDouble()); setFloat(lastFloatIndex + 2 * index + 1, sampler.imageHeight.toDouble()); diff --git a/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart b/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart index 4f42d0e857f47..f47d08d400c29 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart @@ -23,6 +23,11 @@ class CkPathMetrics extends IterableBase late final Iterator iterator = _path.isEmpty ? const CkPathMetricIteratorEmpty._() : CkContourMeasureIter(this); + + /// A fresh [CkContourMeasureIter] which is only used for resurrecting a + /// [CkContourMeasure]. We can't use [iterator] here because [iterator] is + /// memoized. + CkContourMeasureIter _iteratorForResurrection() => CkContourMeasureIter(this); } class CkContourMeasureIter extends ManagedSkiaObject @@ -140,8 +145,7 @@ class CkContourMeasure extends ManagedSkiaObject @override SkContourMeasure resurrect() { - final CkContourMeasureIter iterator = - _metrics.iterator as CkContourMeasureIter; + final CkContourMeasureIter iterator = _metrics._iteratorForResurrection(); final SkContourMeasureIter skIterator = iterator.skiaObject; // When resurrecting we must advance the iterator to the last known diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index 728913ad16342..d0fc7a3ee4bfe 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -327,7 +327,7 @@ class Surface { antialias: _kUsingMSAA ? 1 : 0, majorVersion: webGLVersion, ), - ); + ).toInt(); _glContext = glContext; @@ -429,8 +429,8 @@ class CkSurface { int? get context => _glContext; - int width() => surface.width(); - int height() => surface.height(); + int width() => surface.width().toInt(); + int height() => surface.height().toInt(); void dispose() { if (_isDisposed) { diff --git a/lib/web_ui/lib/src/engine/canvaskit/text.dart b/lib/web_ui/lib/src/engine/canvaskit/text.dart index 67d9630cc6919..0828763cdb531 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/text.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/text.dart @@ -363,15 +363,15 @@ class CkTextStyle implements ui.TextStyle { } if (decoration != null) { - int decorationValue = canvasKit.NoDecoration; + int decorationValue = canvasKit.NoDecoration.toInt(); if (decoration.contains(ui.TextDecoration.underline)) { - decorationValue |= canvasKit.UnderlineDecoration; + decorationValue |= canvasKit.UnderlineDecoration.toInt(); } if (decoration.contains(ui.TextDecoration.overline)) { - decorationValue |= canvasKit.OverlineDecoration; + decorationValue |= canvasKit.OverlineDecoration.toInt(); } if (decoration.contains(ui.TextDecoration.lineThrough)) { - decorationValue |= canvasKit.LineThroughDecoration; + decorationValue |= canvasKit.LineThroughDecoration.toInt(); } properties.decoration = decorationValue; } @@ -785,7 +785,7 @@ class CkParagraph extends SkiaObject implements ui.Paragraph { break; } final SkTextRange skRange = paragraph.getWordBoundary(characterPosition); - return ui.TextRange(start: skRange.start, end: skRange.end); + return ui.TextRange(start: skRange.start.toInt(), end: skRange.end.toInt()); } @override @@ -808,7 +808,7 @@ class CkParagraph extends SkiaObject implements ui.Paragraph { final int offset = position.offset; for (final SkLineMetrics metric in metrics) { if (offset >= metric.startIndex && offset <= metric.endIndex) { - return ui.TextRange(start: metric.startIndex, end: metric.endIndex); + return ui.TextRange(start: metric.startIndex.toInt(), end: metric.endIndex.toInt()); } } return ui.TextRange.empty; @@ -876,7 +876,7 @@ class CkLineMetrics implements ui.LineMetrics { double get width => skLineMetrics.width; @override - int get lineNumber => skLineMetrics.lineNumber; + int get lineNumber => skLineMetrics.lineNumber.toInt(); } class CkParagraphBuilder implements ui.ParagraphBuilder { diff --git a/lib/web_ui/lib/src/engine/canvaskit/util.dart b/lib/web_ui/lib/src/engine/canvaskit/util.dart index 7700abaf28ce7..b1906dac741e9 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/util.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/util.dart @@ -35,9 +35,9 @@ Float32List makeFreshSkColor(ui.Color color) { ui.TextPosition fromPositionWithAffinity(SkTextPosition positionWithAffinity) { final ui.TextAffinity affinity = - ui.TextAffinity.values[positionWithAffinity.affinity.value]; + ui.TextAffinity.values[positionWithAffinity.affinity.value.toInt()]; return ui.TextPosition( - offset: positionWithAffinity.pos, + offset: positionWithAffinity.pos.toInt(), affinity: affinity, ); } diff --git a/lib/web_ui/lib/src/engine/configuration.dart b/lib/web_ui/lib/src/engine/configuration.dart index 3cd9d1d5644f4..1e89528992962 100644 --- a/lib/web_ui/lib/src/engine/configuration.dart +++ b/lib/web_ui/lib/src/engine/configuration.dart @@ -204,7 +204,8 @@ class FlutterConfiguration { /// /// This value can be specified using either the `FLUTTER_WEB_MAXIMUM_SURFACES` /// environment variable, or using the runtime configuration. - int get canvasKitMaximumSurfaces => _configuration?.canvasKitMaximumSurfaces ?? _defaultCanvasKitMaximumSurfaces; + int get canvasKitMaximumSurfaces => + _configuration?.canvasKitMaximumSurfaces?.toInt() ?? _defaultCanvasKitMaximumSurfaces; static const int _defaultCanvasKitMaximumSurfaces = int.fromEnvironment( 'FLUTTER_WEB_MAXIMUM_SURFACES', defaultValue: 8, @@ -251,7 +252,7 @@ class JsFlutterConfiguration {} extension JsFlutterConfigurationExtension on JsFlutterConfiguration { external String? get canvasKitBaseUrl; external bool? get canvasKitForceCpuOnly; - external int? get canvasKitMaximumSurfaces; + external double? get canvasKitMaximumSurfaces; external bool? get debugShowSemanticsNodes; external DomElement? get hostElement; external String? get renderer; diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 0975d736212e4..8d60a25b358a7 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -28,13 +28,11 @@ class DomWindow extends DomEventTarget {} extension DomWindowExtension on DomWindow { external DomConsole get console; - external num get devicePixelRatio; + external double get devicePixelRatio; external DomDocument get document; external DomHistory get history; - int? get innerHeight => - js_util.getProperty(this, 'innerHeight')?.toInt(); - int? get innerWidth => - js_util.getProperty(this, 'innerWidth')?.toInt(); + external double? get innerHeight; + external double? get innerWidth; external DomLocation get location; external DomNavigator get navigator; external DomVisualViewport? get visualViewport; @@ -52,9 +50,7 @@ extension DomWindowExtension on DomWindow { if (pseudoElt != null) pseudoElt ]) as DomCSSStyleDeclaration; external DomScreen? get screen; - int requestAnimationFrame(DomRequestAnimationFrameCallback callback) => - js_util.callMethod(this, 'requestAnimationFrame', - [callback]).toInt(); + external double requestAnimationFrame(DomRequestAnimationFrameCallback callback); void postMessage(Object message, String targetOrigin, [List? messagePorts]) => js_util.callMethod(this, 'postMessage', [ @@ -92,8 +88,7 @@ class DomNavigator {} extension DomNavigatorExtension on DomNavigator { external DomClipboard? get clipboard; - int? get maxTouchPoints => - js_util.getProperty(this, 'maxTouchPoints')?.toInt(); + external double? get maxTouchPoints; external String get vendor; external String get language; external String? get platform; @@ -179,7 +174,7 @@ class DomEvent {} extension DomEventExtension on DomEvent { external DomEventTarget? get target; - external num? get timeStamp; + external double? get timeStamp; external String get type; external void preventDefault(); external void stopPropagation(); @@ -203,10 +198,8 @@ DomEvent createDomEvent(String type, String name) { class DomProgressEvent extends DomEvent {} extension DomProgressEventExtension on DomProgressEvent { - int? get loaded => - js_util.getProperty(this, 'loaded')?.toInt(); - int? get total => - js_util.getProperty(this, 'total')?.toInt(); + external double? get loaded; + external double? get total; } @JS() @@ -257,10 +250,8 @@ DomElement createDomElement(String tag) => domDocument.createElement(tag); extension DomElementExtension on DomElement { Iterable get children => createDomListWrapper( js_util.getProperty<_DomList>(this, 'children')); - int get clientHeight => - js_util.getProperty(this, 'clientHeight').toInt(); - int get clientWidth => - js_util.getProperty(this, 'clientWidth').toInt(); + external double get clientHeight; + external double get clientWidth; external String get id; external set id(String id); external set innerHtml(String? html); @@ -280,18 +271,13 @@ extension DomElementExtension on DomElement { external void setAttribute(String name, Object value); void appendText(String text) => append(createDomText(text)); external void removeAttribute(String name); - set tabIndex(int? value) => - js_util.setProperty(this, 'tabIndex', value?.toDouble()); - int? get tabIndex => - js_util.getProperty(this, 'tabIndex')?.toInt(); + external set tabIndex(double? value); + external double? get tabIndex; external void focus(); - int get scrollTop => js_util.getProperty(this, 'scrollTop').toInt(); - set scrollTop(int value) => - js_util.setProperty(this, 'scrollTop', value.toDouble()); - int get scrollLeft => - js_util.getProperty(this, 'scrollLeft').toInt(); - set scrollLeft(int value) => - js_util.setProperty(this, 'scrollLeft', value.toDouble()); + external double get scrollTop; + external set scrollTop(double value); + external double get scrollLeft; + external set scrollLeft(double value); external DomTokenList get classList; external set className(String value); external String get className; @@ -471,8 +457,7 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration { class DomHTMLElement extends DomElement {} extension DomHTMLElementExtension on DomHTMLElement { - int get offsetWidth => - js_util.getProperty(this, 'offsetWidth').toInt(); + external double get offsetWidth; } @JS() @@ -510,14 +495,10 @@ extension DomHTMLImageElementExtension on DomHTMLImageElement { external set alt(String? value); external String? get src; external set src(String? value); - int get naturalWidth => - js_util.getProperty(this, 'naturalWidth').toInt(); - int get naturalHeight => - js_util.getProperty(this, 'naturalHeight').toInt(); - set width(int? value) => - js_util.setProperty(this, 'width', value?.toDouble()); - set height(int? value) => - js_util.setProperty(this, 'height', value?.toDouble()); + external double get naturalWidth; + external double get naturalHeight; + external set width(double? value); + external set height(double? value); Future decode() => js_util.promiseToFuture(js_util.callMethod(this, 'decode', [])); } @@ -600,23 +581,19 @@ DomCanvasElement createDomCanvasElement({int? width, int? height}) { final DomCanvasElement canvas = domWindow.document.createElement('canvas') as DomCanvasElement; if (width != null) { - canvas.width = width; + canvas.width = width.toDouble(); } if (height != null) { - canvas.height = height; + canvas.height = height.toDouble(); } return canvas; } extension DomCanvasElementExtension on DomCanvasElement { - int? get width => - js_util.getProperty(this, 'width')?.toInt(); - set width(int? value) => - js_util.setProperty(this, 'width', value?.toDouble()); - int? get height => - js_util.getProperty(this, 'height')?.toInt(); - set height(int? value) => - js_util.setProperty(this, 'height', value?.toDouble()); + external double? get width; + external set width(double? value); + external double? get height; + external set height(double? value); external bool? get isConnected; String toDataURL([String type = 'image/png']) => js_util.callMethod(this, 'toDataURL', [type]); @@ -752,8 +729,7 @@ extension DomXMLHttpRequestExtension on DomXMLHttpRequest { external dynamic get response; external String? get responseText; external String get responseType; - int? get status => - js_util.getProperty(this, 'status')?.toInt(); + external double? get status; external set responseType(String value); void open(String method, String url, [bool? async]) => js_util.callMethod( this, 'open', [method, url, if (async != null) async]); @@ -771,7 +747,7 @@ Future domHttpRequest(String url, } xhr.addEventListener('load', allowInterop((DomEvent e) { - final int status = xhr.status!; + final int status = xhr.status!.toInt(); final bool accepted = status >= 200 && status < 300; final bool fileUri = status == 0; final bool notModified = status == 304; @@ -807,7 +783,7 @@ DomText createDomText(String data) => domDocument.createTextNode(data); class DomTextMetrics {} extension DomTextMetricsExtension on DomTextMetrics { - external num? get width; + external double? get width; } @JS() @@ -825,14 +801,14 @@ extension DomExceptionExtension on DomException { class DomRectReadOnly {} extension DomRectReadOnlyExtension on DomRectReadOnly { - external num get x; - external num get y; - external num get width; - external num get height; - external num get top; - external num get right; - external num get bottom; - external num get left; + external double get x; + external double get y; + external double get width; + external double get height; + external double get top; + external double get right; + external double get bottom; + external double get left; } DomRect createDomRectFromPoints(DomPoint a, DomPoint b) { @@ -884,8 +860,8 @@ typedef DomFontFaceSetForEachCallback = void Function( class DomVisualViewport extends DomEventTarget {} extension DomVisualViewportExtension on DomVisualViewport { - external num? get height; - external num? get width; + external double? get height; + external double? get width; } @JS() @@ -900,10 +876,10 @@ extension DomHTMLTextAreaElementExtension on DomHTMLTextAreaElement { external void select(); external set placeholder(String? value); external set name(String value); - external int? get selectionStart; - external int? get selectionEnd; - external set selectionStart(int? value); - external set selectionEnd(int? value); + external double? get selectionStart; + external double? get selectionEnd; + external set selectionStart(double? value); + external set selectionEnd(double? value); external String? get value; void setSelectionRange(int start, int end, [String? direction]) => js_util.callMethod(this, 'setSelectionRange', @@ -949,10 +925,8 @@ extension DomKeyboardEventExtension on DomKeyboardEvent { external String? get code; external bool get ctrlKey; external String? get key; - int get keyCode => - js_util.getProperty(this, 'keyCode').toInt(); - int get location => - js_util.getProperty(this, 'location').toInt(); + external double get keyCode; + external double get location; external bool get metaKey; external bool? get repeat; external bool get shiftKey; @@ -1107,16 +1081,14 @@ DomPath2D createDomPath2D([Object? path]) => class DomMouseEvent extends DomUIEvent {} extension DomMouseEventExtension on DomMouseEvent { - external num get clientX; - external num get clientY; - external num get offsetX; - external num get offsetY; + external double get clientX; + external double get clientY; + external double get offsetX; + external double get offsetY; DomPoint get client => DomPoint(clientX, clientY); DomPoint get offset => DomPoint(offsetX, offsetY); - int get button => - js_util.getProperty(this, 'button').toInt(); - int? get buttons => - js_util.getProperty(this, 'buttons')?.toInt(); + external double get button; + external double? get buttons; external bool getModifierState(String keyArg); } @@ -1129,14 +1101,11 @@ DomMouseEvent createDomMouseEvent(String type, [Map? init]) => class DomPointerEvent extends DomMouseEvent {} extension DomPointerEventExtension on DomPointerEvent { - int? get pointerId => - js_util.getProperty(this, 'pointerId')?.toInt(); + external double? get pointerId; external String? get pointerType; - external num? get pressure; - int? get tiltX => - js_util.getProperty(this, 'tiltX')?.toInt(); - int? get tiltY => - js_util.getProperty(this, 'tiltY')?.toInt(); + external double? get pressure; + external double? get tiltX; + external double? get tiltY; List getCoalescedEvents() => js_util.callMethod>( this, 'getCoalescedEvents', []).cast(); @@ -1152,10 +1121,9 @@ DomPointerEvent createDomPointerEvent(String type, class DomWheelEvent extends DomMouseEvent {} extension DomWheelEventExtension on DomWheelEvent { - external num get deltaX; - external num get deltaY; - int get deltaMode => - js_util.getProperty(this, 'deltaMode').toInt(); + external double get deltaX; + external double get deltaY; + external double get deltaMode; } @JS() @@ -1177,10 +1145,9 @@ extension DomTouchEventExtension on DomTouchEvent { class DomTouch {} extension DomTouchExtension on DomTouch { - int? get identifier => - js_util.getProperty(this, 'identifier')?.toInt(); - external num get clientX; - external num get clientY; + external double? get identifier; + external double get clientX; + external double get clientY; DomPoint get client => DomPoint(clientX, clientY); } @@ -1220,14 +1187,10 @@ extension DomHTMLInputElementExtension on DomHTMLInputElement { external set placeholder(String? value); external set name(String? value); external set autocomplete(String value); - int? get selectionStart => - js_util.getProperty(this, 'selectionStart')?.toInt(); - int? get selectionEnd => - js_util.getProperty(this, 'selectionEnd')?.toInt(); - set selectionStart(int? value) => - js_util.setProperty(this, 'selectionStart', value?.toDouble()); - set selectionEnd(int? value) => - js_util.setProperty(this, 'selectionEnd', value?.toDouble()); + external double? get selectionStart; + external double? get selectionEnd; + external set selectionStart(double? value); + external set selectionEnd(double? value); void setSelectionRange(int start, int end, [String? direction]) => js_util.callMethod(this, 'setSelectionRange', [start.toDouble(), end.toDouble(), @@ -1276,14 +1239,10 @@ DomHTMLLabelElement createDomHTMLLabelElement() => class DomOffscreenCanvas extends DomEventTarget {} extension DomOffscreenCanvasExtension on DomOffscreenCanvas { - int? get height => - js_util.getProperty(this, 'height')?.toInt(); - int? get width => - js_util.getProperty(this, 'width')?.toInt(); - set height(int? value) => - js_util.setProperty(this, 'height', value?.toDouble()); - set width(int? value) => - js_util.setProperty(this, 'width', value?.toDouble()); + external double? get height; + external double? get width; + external set height(double? value); + external set width(double? value); Object? getContext(String contextType, [Map? attributes]) { return js_util.callMethod(this, 'getContext', [ contextType, @@ -1348,10 +1307,10 @@ class DomCSSStyleSheet extends DomStyleSheet {} extension DomCSSStyleSheetExtension on DomCSSStyleSheet { external DomCSSRuleList get cssRules; - int insertRule(String rule, [int? index]) => js_util + double insertRule(String rule, [int? index]) => js_util .callMethod( this, 'insertRule', - [rule, if (index != null) index.toDouble()]).toInt(); + [rule, if (index != null) index.toDouble()]); } @JS() @@ -1460,8 +1419,7 @@ extension DomMessageChannelExtension on DomMessageChannel { class DomCSSRuleList {} extension DomCSSRuleListExtension on DomCSSRuleList { - int get length => - js_util.getProperty(this, 'length').toInt(); + external double get length; } /// A factory to create `TrustedTypePolicy` objects. @@ -1620,8 +1578,7 @@ bool domInstanceOfString(Object? element, String objectType) => class _DomList {} extension DomListExtension on _DomList { - int get length => - js_util.getProperty(this, 'length').toInt(); + external double get length; DomNode item(int index) => js_util.callMethod(this, 'item', [index.toDouble()]); } @@ -1655,7 +1612,7 @@ class _DomListWrapper extends Iterable { /// Override the length to avoid iterating through the whole collection. @override - int get length => list.length; + int get length => list.length.toInt(); } /// This is a work around for a `TypeError` which can be triggered by calling @@ -1681,9 +1638,9 @@ class DomV8BreakIterator {} extension DomV8BreakIteratorExtension on DomV8BreakIterator { external void adoptText(String text); - external int first(); - external int next(); - external int current(); + external double first(); + external double next(); + external double current(); external String breakType(); } diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart index 42479a07c8b2f..0c98a3d259d86 100644 --- a/lib/web_ui/lib/src/engine/embedder.dart +++ b/lib/web_ui/lib/src/engine/embedder.dart @@ -340,7 +340,7 @@ class FlutterViewEmbedder { // Firefox returns correct values for innerHeight, innerWidth. // Firefox also triggers domWindow.onResize therefore this timer does // not need to be set up for Firefox. - final int initialInnerWidth = domWindow.innerWidth!; + final int initialInnerWidth = domWindow.innerWidth!.toInt(); // Counts how many times screen size was checked. It is checked up to 5 // times. int checkCount = 0; @@ -551,7 +551,7 @@ void applyGlobalCssRulesToSheet( // - See: https://github.com/flutter/flutter/issues/44803 sheet.insertRule( 'flt-paragraph, flt-span {line-height: 100%;}', - sheet.cssRules.length, + sheet.cssRules.length.toInt(), ); } @@ -571,7 +571,7 @@ void applyGlobalCssRulesToSheet( left: 0; } ''', - sheet.cssRules.length, + sheet.cssRules.length.toInt(), ); if (isWebKit) { @@ -579,7 +579,7 @@ void applyGlobalCssRulesToSheet( 'flt-semantics input[type=range]::-webkit-slider-thumb {' ' -webkit-appearance: none;' '}', - sheet.cssRules.length); + sheet.cssRules.length.toInt()); } if (isFirefox) { @@ -587,12 +587,12 @@ void applyGlobalCssRulesToSheet( 'input::-moz-selection {' ' background-color: transparent;' '}', - sheet.cssRules.length); + sheet.cssRules.length.toInt()); sheet.insertRule( 'textarea::-moz-selection {' ' background-color: transparent;' '}', - sheet.cssRules.length); + sheet.cssRules.length.toInt()); } else { // On iOS, the invisible semantic text field has a visible cursor and // selection highlight. The following 2 CSS rules force everything to be @@ -601,12 +601,12 @@ void applyGlobalCssRulesToSheet( 'input::selection {' ' background-color: transparent;' '}', - sheet.cssRules.length); + sheet.cssRules.length.toInt()); sheet.insertRule( 'textarea::selection {' ' background-color: transparent;' '}', - sheet.cssRules.length); + sheet.cssRules.length.toInt()); } sheet.insertRule(''' flt-semantics input, @@ -614,7 +614,7 @@ void applyGlobalCssRulesToSheet( flt-semantics [contentEditable="true"] { caret-color: transparent; } - ''', sheet.cssRules.length); + ''', sheet.cssRules.length.toInt()); // By default on iOS, Safari would highlight the element that's being tapped // on using gray background. This CSS rule disables that. @@ -623,7 +623,7 @@ void applyGlobalCssRulesToSheet( $glassPaneTagName * { -webkit-tap-highlight-color: transparent; } - ''', sheet.cssRules.length); + ''', sheet.cssRules.length.toInt()); } // Hide placeholder text @@ -633,7 +633,7 @@ void applyGlobalCssRulesToSheet( opacity: 0; } ''', - sheet.cssRules.length, + sheet.cssRules.length.toInt(), ); // This css prevents an autofill overlay brought by the browser during @@ -647,7 +647,7 @@ void applyGlobalCssRulesToSheet( .transparentTextEditing:-webkit-autofill:active { -webkit-transition-delay: 99999s; } - ''', sheet.cssRules.length); + ''', sheet.cssRules.length.toInt()); } } diff --git a/lib/web_ui/lib/src/engine/html/image_filter.dart b/lib/web_ui/lib/src/engine/html/image_filter.dart index 7fe37f641be43..13de22ab993a0 100644 --- a/lib/web_ui/lib/src/engine/html/image_filter.dart +++ b/lib/web_ui/lib/src/engine/html/image_filter.dart @@ -7,22 +7,54 @@ import 'package:ui/ui.dart' as ui; import '../color_filter.dart'; import '../dom.dart'; import '../embedder.dart'; +import '../util.dart'; +import '../vector_math.dart'; import 'shaders/shader.dart'; import 'surface.dart'; +import 'surface_stats.dart'; /// A surface that applies an [imageFilter] to its children. class PersistedImageFilter extends PersistedContainerSurface implements ui.ImageFilterEngineLayer { - PersistedImageFilter(PersistedImageFilter? super.oldLayer, this.filter); + PersistedImageFilter(PersistedImageFilter? super.oldLayer, this.filter, this.offset); final ui.ImageFilter filter; + final ui.Offset offset; + + @override + void recomputeTransformAndClip() { + transform = parent!.transform; + + final double dx = offset.dx; + final double dy = offset.dy; + + if (dx != 0.0 || dy != 0.0) { + transform = transform!.clone(); + transform!.translate(dx, dy); + } + projectedClip = null; + } + + /// Cached inverse of transform on this node. Unlike transform, this + /// Matrix only contains local transform (not chain multiplied since root). + Matrix4? _localTransformInverse; + + @override + Matrix4 get localTransformInverse => _localTransformInverse ??= + Matrix4.translationValues(-offset.dx, -offset.dy, 0); DomElement? _svgFilter; + @override + DomElement? get childContainer => _childContainer; + DomElement? _childContainer; @override void adoptElements(PersistedImageFilter oldSurface) { super.adoptElements(oldSurface); _svgFilter = oldSurface._svgFilter; + _childContainer = oldSurface._childContainer; + oldSurface._svgFilter = null; + oldSurface._childContainer = null; } @override @@ -30,11 +62,26 @@ class PersistedImageFilter extends PersistedContainerSurface super.discard(); flutterViewEmbedder.removeResource(_svgFilter); _svgFilter = null; + _childContainer = null; } @override DomElement createElement() { - return defaultCreateElement('flt-image-filter'); + final DomElement element = defaultCreateElement('flt-image-filter'); + final DomElement container = defaultCreateElement('flt-image-filter-interior'); + if (debugExplainSurfaceStats) { + // This creates an additional interior element. Count it too. + surfaceStatsFor(this).allocatedDomNodeCount++; + } + + setElementStyle(container, 'position', 'absolute'); + setElementStyle(container, 'transform-origin', '0 0 0'); + setElementStyle(element, 'position', 'absolute'); + setElementStyle(element, 'transform-origin', '0 0 0'); + + _childContainer = container; + element.appendChild(container); + return element; } @override @@ -57,15 +104,18 @@ class PersistedImageFilter extends PersistedContainerSurface _svgFilter = backendFilter.makeSvgFilter(rootElement); } - rootElement!.style.filter = backendFilter.filterAttribute; - rootElement!.style.transform = backendFilter.transformAttribute; + _childContainer!.style.filter = backendFilter.filterAttribute; + _childContainer!.style.transform = backendFilter.transformAttribute; + rootElement!.style + ..left = '${offset.dx}px' + ..top = '${offset.dy}px'; } @override void update(PersistedImageFilter oldSurface) { super.update(oldSurface); - if (oldSurface.filter != filter) { + if (oldSurface.filter != filter || oldSurface.offset != offset) { apply(); } } diff --git a/lib/web_ui/lib/src/engine/html/painting.dart b/lib/web_ui/lib/src/engine/html/painting.dart index dc3ccdc4f63a7..bdd8aa4fd8251 100644 --- a/lib/web_ui/lib/src/engine/html/painting.dart +++ b/lib/web_ui/lib/src/engine/html/painting.dart @@ -303,7 +303,7 @@ class HtmlFragmentShader implements ui.FragmentShader { } @override - void setSampler(int index, ui.ImageShader sampler) { + void setImageSampler(int index, ui.Image image) { throw UnsupportedError('FragmentShader is not supported for the HTML renderer.'); } diff --git a/lib/web_ui/lib/src/engine/html/scene.dart b/lib/web_ui/lib/src/engine/html/scene.dart index 44831d6a8876c..9beba6a4a6537 100644 --- a/lib/web_ui/lib/src/engine/html/scene.dart +++ b/lib/web_ui/lib/src/engine/html/scene.dart @@ -48,8 +48,8 @@ class PersistedScene extends PersistedContainerSurface { // TODO(yjbanov): in the add2app scenario where we might be hosted inside // a custom element, this will be different. We will need to // update this code when we add add2app support. - final double screenWidth = domWindow.innerWidth!.toDouble(); - final double screenHeight = domWindow.innerHeight!.toDouble(); + final double screenWidth = domWindow.innerWidth!; + final double screenHeight = domWindow.innerHeight!; localClipBounds = ui.Rect.fromLTRB(0, 0, screenWidth, screenHeight); projectedClip = null; } diff --git a/lib/web_ui/lib/src/engine/html/scene_builder.dart b/lib/web_ui/lib/src/engine/html/scene_builder.dart index 1e552b15b5fc5..bd84aeaf9a992 100644 --- a/lib/web_ui/lib/src/engine/html/scene_builder.dart +++ b/lib/web_ui/lib/src/engine/html/scene_builder.dart @@ -223,11 +223,12 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { @override ui.ImageFilterEngineLayer pushImageFilter( ui.ImageFilter filter, { + ui.Offset offset = ui.Offset.zero, ui.ImageFilterEngineLayer? oldLayer, }) { assert(filter != null); return _pushSurface( - PersistedImageFilter(oldLayer as PersistedImageFilter?, filter)); + PersistedImageFilter(oldLayer as PersistedImageFilter?, filter, offset)); } /// Pushes a backdrop filter operation onto the operation stack. diff --git a/lib/web_ui/lib/src/engine/html/surface_stats.dart b/lib/web_ui/lib/src/engine/html/surface_stats.dart index 339bf85ec2d05..841c318c441ed 100644 --- a/lib/web_ui/lib/src/engine/html/surface_stats.dart +++ b/lib/web_ui/lib/src/engine/html/surface_stats.dart @@ -97,7 +97,7 @@ class DebugSurfaceStats { DomCanvasRenderingContext2D? _debugSurfaceStatsOverlayCtx; void debugRepaintSurfaceStatsOverlay(PersistedScene scene) { - final int overlayWidth = domWindow.innerWidth!; + final int overlayWidth = domWindow.innerWidth!.toInt(); const int rowHeight = 30; const int rowCount = 4; const int overlayHeight = rowHeight * rowCount; @@ -296,7 +296,7 @@ void debugPrintSurfaceStats(PersistedScene scene, int frameNumber) { final int pixelCount = canvasElements .cast() .map((DomCanvasElement e) { - final int pixels = e.width! * e.height!; + final int pixels = (e.width! * e.height!).toInt(); canvasInfo.writeln(' - ${e.width!} x ${e.height!} = $pixels pixels'); return pixels; }).fold(0, (int total, int pixels) => total + pixels); diff --git a/lib/web_ui/lib/src/engine/html_image_codec.dart b/lib/web_ui/lib/src/engine/html_image_codec.dart index 11c4d29428d4d..d5db33fcbffc1 100644 --- a/lib/web_ui/lib/src/engine/html_image_codec.dart +++ b/lib/web_ui/lib/src/engine/html_image_codec.dart @@ -53,8 +53,8 @@ class HtmlCodec implements ui.Codec { // ignore: unawaited_futures imgElement.decode().then((dynamic _) { chunkCallback?.call(100, 100); - int naturalWidth = imgElement.naturalWidth; - int naturalHeight = imgElement.naturalHeight; + int naturalWidth = imgElement.naturalWidth.toInt(); + int naturalHeight = imgElement.naturalHeight.toInt(); // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=700533. if (naturalWidth == 0 && naturalHeight == 0 && browserEngine == BrowserEngine.firefox) { const int kDefaultImageSizeFallback = 300; @@ -103,8 +103,8 @@ class HtmlCodec implements ui.Codec { imgElement.removeEventListener('error', errorListener); final HtmlImage image = HtmlImage( imgElement, - imgElement.naturalWidth, - imgElement.naturalHeight, + imgElement.naturalWidth.toInt(), + imgElement.naturalHeight.toInt(), ); completer.complete(SingleFrameInfo(image)); }); @@ -143,7 +143,7 @@ class HtmlImage implements ui.Image { } final DomHTMLImageElement imgElement; - bool _requiresClone = false; + bool _didClone = false; bool _disposed = false; @override @@ -188,8 +188,8 @@ class HtmlImage implements ui.Image { case ui.ImageByteFormat.rawRgba: case ui.ImageByteFormat.rawStraightRgba: final DomCanvasElement canvas = createDomCanvasElement() - ..width = width - ..height = height; + ..width = width.toDouble() + ..height = height.toDouble(); final DomCanvasRenderingContext2D ctx = canvas.context2D; ctx.drawImage(imgElement, 0, 0); final DomImageData imageData = ctx.getImageData(0, 0, width, height); @@ -204,16 +204,12 @@ class HtmlImage implements ui.Image { } } - // Returns absolutely positioned actual image element on first call and - // clones on subsequent calls. DomHTMLImageElement cloneImageElement() { - if (_requiresClone) { - return imgElement.cloneNode(true) as DomHTMLImageElement; - } else { - _requiresClone = true; + if (!_didClone) { + _didClone = true; imgElement.style.position = 'absolute'; - return imgElement; } + return imgElement.cloneNode(true) as DomHTMLImageElement; } @override diff --git a/lib/web_ui/lib/src/engine/keyboard_binding.dart b/lib/web_ui/lib/src/engine/keyboard_binding.dart index b5403ac3eedee..0e8226a15aa01 100644 --- a/lib/web_ui/lib/src/engine/keyboard_binding.dart +++ b/lib/web_ui/lib/src/engine/keyboard_binding.dart @@ -190,9 +190,9 @@ class FlutterHtmlKeyboardEvent { String get type => _event.type; String? get code => _event.code; String? get key => _event.key; - int get keyCode => _event.keyCode; + int get keyCode => _event.keyCode.toInt(); bool? get repeat => _event.repeat; - int? get location => _event.location; + int? get location => _event.location.toInt(); num? get timeStamp => _event.timeStamp; bool get altKey => _event.altKey; bool get ctrlKey => _event.ctrlKey; diff --git a/lib/web_ui/lib/src/engine/picture.dart b/lib/web_ui/lib/src/engine/picture.dart index 074dc9f27856d..3b9083ff04231 100644 --- a/lib/web_ui/lib/src/engine/picture.dart +++ b/lib/web_ui/lib/src/engine/picture.dart @@ -64,8 +64,8 @@ class EnginePicture implements ui.Picture { final String imageDataUrl = canvas.toDataUrl(); final DomHTMLImageElement imageElement = createDomHTMLImageElement() ..src = imageDataUrl - ..width = width - ..height = height; + ..width = width.toDouble() + ..height = height.toDouble(); // The image loads asynchronously. We need to wait before returning, // otherwise the returned HtmlImage will be temporarily unusable. diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index 3cfbffeb1fcc2..e7d6f80b7f355 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -185,9 +185,9 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { /// Returns device pixel ratio returned by browser. static double get browserDevicePixelRatio { - final double? ratio = domWindow.devicePixelRatio as double?; - // Guard against WebOS returning 0 and other browsers returning null. - return (ratio == null || ratio == 0.0) ? 1.0 : ratio; + final double ratio = domWindow.devicePixelRatio; + // Guard against WebOS returning 0. + return (ratio == 0.0) ? 1.0 : ratio; } /// A callback invoked when any window begins a frame. diff --git a/lib/web_ui/lib/src/engine/pointer_binding.dart b/lib/web_ui/lib/src/engine/pointer_binding.dart index 72f646c7c473a..639814d3a9dfb 100644 --- a/lib/web_ui/lib/src/engine/pointer_binding.dart +++ b/lib/web_ui/lib/src/engine/pointer_binding.dart @@ -342,9 +342,9 @@ mixin _WheelEventListenerMixin on _BaseAdapter { // Flutter only supports pixel scroll delta. Convert deltaMode values // to pixels. - double deltaX = event.deltaX as double; - double deltaY = event.deltaY as double; - switch (event.deltaMode) { + double deltaX = event.deltaX; + double deltaY = event.deltaY; + switch (event.deltaMode.toInt()) { case domDeltaLine: _defaultScrollLineHeight ??= _computeDefaultScrollLineHeight(); deltaX *= _defaultScrollLineHeight!; @@ -374,9 +374,9 @@ mixin _WheelEventListenerMixin on _BaseAdapter { kind: ui.PointerDeviceKind.mouse, signalKind: ui.PointerSignalKind.scroll, device: _mouseDeviceId, - physicalX: event.clientX.toDouble() * ui.window.devicePixelRatio, - physicalY: event.clientY.toDouble() * ui.window.devicePixelRatio, - buttons: event.buttons!, + physicalX: event.clientX * ui.window.devicePixelRatio, + physicalY: event.clientY * ui.window.devicePixelRatio, + buttons: event.buttons!.toInt(), pressure: 1.0, pressureMax: 1.0, scrollDeltaX: deltaX, @@ -647,14 +647,14 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin { final List pointerData = []; final _ButtonSanitizer sanitizer = _ensureSanitizer(device); final _SanitizedDetails? up = - sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!); + sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!.toInt()); if (up != null) { _convertEventsToPointerData(data: pointerData, event: event, details: up); } final _SanitizedDetails down = sanitizer.sanitizeDownEvent( - button: event.button, - buttons: event.buttons!, + button: event.button.toInt(), + buttons: event.buttons!.toInt(), ); _convertEventsToPointerData(data: pointerData, event: event, details: down); _callback(pointerData); @@ -666,11 +666,11 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin { final List pointerData = []; final List expandedEvents = _expandEvents(event); for (final DomPointerEvent event in expandedEvents) { - final _SanitizedDetails? up = sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!); + final _SanitizedDetails? up = sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!.toInt()); if (up != null) { _convertEventsToPointerData(data: pointerData, event: event, details: up); } - final _SanitizedDetails move = sanitizer.sanitizeMoveEvent(buttons: event.buttons!); + final _SanitizedDetails move = sanitizer.sanitizeMoveEvent(buttons: event.buttons!.toInt()); _convertEventsToPointerData(data: pointerData, event: event, details: move); } _callback(pointerData); @@ -680,7 +680,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin { final int device = _getPointerId(event); final _ButtonSanitizer sanitizer = _ensureSanitizer(device); final List pointerData = []; - final _SanitizedDetails? details = sanitizer.sanitizeLeaveEvent(buttons: event.buttons!); + final _SanitizedDetails? details = sanitizer.sanitizeLeaveEvent(buttons: event.buttons!.toInt()); if (details != null) { _convertEventsToPointerData(data: pointerData, event: event, details: details); _callback(pointerData); @@ -691,7 +691,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin { final int device = _getPointerId(event); if (_hasSanitizer(device)) { final List pointerData = []; - final _SanitizedDetails? details = _getSanitizer(device).sanitizeUpEvent(buttons: event.buttons); + final _SanitizedDetails? details = _getSanitizer(device).sanitizeUpEvent(buttons: event.buttons?.toInt()); _removePointerIfUnhoverable(event); if (details != null) { _convertEventsToPointerData(data: pointerData, event: event, details: details); @@ -739,8 +739,8 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin { kind: kind, signalKind: ui.PointerSignalKind.none, device: _getPointerId(event), - physicalX: event.clientX.toDouble() * ui.window.devicePixelRatio, - physicalY: event.clientY.toDouble() * ui.window.devicePixelRatio, + physicalX: event.clientX * ui.window.devicePixelRatio, + physicalY: event.clientY * ui.window.devicePixelRatio, buttons: details.buttons, pressure: pressure == null ? 0.0 : pressure.toDouble(), pressureMax: 1.0, @@ -781,12 +781,13 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin { // might come before any PointerEvents, and since wheel events don't contain // pointerId we always assign `device: _mouseDeviceId` to them. final ui.PointerDeviceKind kind = _pointerTypeToDeviceKind(event.pointerType!); - return kind == ui.PointerDeviceKind.mouse ? _mouseDeviceId : event.pointerId!; + return kind == ui.PointerDeviceKind.mouse ? _mouseDeviceId : + event.pointerId!.toInt(); } /// Tilt angle is -90 to + 90. Take maximum deflection and convert to radians. double _computeHighestTilt(DomPointerEvent e) => - (e.tiltX!.abs() > e.tiltY!.abs() ? e.tiltX : e.tiltY)!.toDouble() / + (e.tiltX!.abs() > e.tiltY!.abs() ? e.tiltX : e.tiltY)! / 180.0 * math.pi; } @@ -833,9 +834,9 @@ class _TouchAdapter extends _BaseAdapter { final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); final List pointerData = []; for (final DomTouch touch in event.changedTouches!.cast()) { - final bool nowPressed = _isTouchPressed(touch.identifier!); + final bool nowPressed = _isTouchPressed(touch.identifier!.toInt()); if (!nowPressed) { - _pressTouch(touch.identifier!); + _pressTouch(touch.identifier!.toInt()); _convertEventToPointerData( data: pointerData, change: ui.PointerChange.down, @@ -853,7 +854,7 @@ class _TouchAdapter extends _BaseAdapter { final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); final List pointerData = []; for (final DomTouch touch in event.changedTouches!.cast()) { - final bool nowPressed = _isTouchPressed(touch.identifier!); + final bool nowPressed = _isTouchPressed(touch.identifier!.toInt()); if (nowPressed) { _convertEventToPointerData( data: pointerData, @@ -874,9 +875,9 @@ class _TouchAdapter extends _BaseAdapter { final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); final List pointerData = []; for (final DomTouch touch in event.changedTouches!.cast()) { - final bool nowPressed = _isTouchPressed(touch.identifier!); + final bool nowPressed = _isTouchPressed(touch.identifier!.toInt()); if (nowPressed) { - _unpressTouch(touch.identifier!); + _unpressTouch(touch.identifier!.toInt()); _convertEventToPointerData( data: pointerData, change: ui.PointerChange.up, @@ -893,9 +894,9 @@ class _TouchAdapter extends _BaseAdapter { final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); final List pointerData = []; for (final DomTouch touch in event.changedTouches!.cast()) { - final bool nowPressed = _isTouchPressed(touch.identifier!); + final bool nowPressed = _isTouchPressed(touch.identifier!.toInt()); if (nowPressed) { - _unpressTouch(touch.identifier!); + _unpressTouch(touch.identifier!.toInt()); _convertEventToPointerData( data: pointerData, change: ui.PointerChange.cancel, @@ -921,9 +922,9 @@ class _TouchAdapter extends _BaseAdapter { change: change, timeStamp: timeStamp, signalKind: ui.PointerSignalKind.none, - device: touch.identifier!, - physicalX: touch.clientX.toDouble() * ui.window.devicePixelRatio, - physicalY: touch.clientY.toDouble() * ui.window.devicePixelRatio, + device: touch.identifier!.toInt(), + physicalX: touch.clientX * ui.window.devicePixelRatio, + physicalY: touch.clientY * ui.window.devicePixelRatio, buttons: pressed ? _kPrimaryMouseButton : 0, pressure: 1.0, pressureMax: 1.0, @@ -992,14 +993,14 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin { _addMouseEventListener(glassPaneElement, 'mousedown', (DomMouseEvent event) { final List pointerData = []; final _SanitizedDetails? up = - _sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!); + _sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!.toInt()); if (up != null) { _convertEventsToPointerData(data: pointerData, event: event, details: up); } final _SanitizedDetails sanitizedDetails = _sanitizer.sanitizeDownEvent( - button: event.button, - buttons: event.buttons!, + button: event.button.toInt(), + buttons: event.buttons!.toInt(), ); _convertEventsToPointerData(data: pointerData, event: event, details: sanitizedDetails); _callback(pointerData); @@ -1007,18 +1008,18 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin { _addMouseEventListener(domWindow, 'mousemove', (DomMouseEvent event) { final List pointerData = []; - final _SanitizedDetails? up = _sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!); + final _SanitizedDetails? up = _sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!.toInt()); if (up != null) { _convertEventsToPointerData(data: pointerData, event: event, details: up); } - final _SanitizedDetails move = _sanitizer.sanitizeMoveEvent(buttons: event.buttons!); + final _SanitizedDetails move = _sanitizer.sanitizeMoveEvent(buttons: event.buttons!.toInt()); _convertEventsToPointerData(data: pointerData, event: event, details: move); _callback(pointerData); }); _addMouseEventListener(glassPaneElement, 'mouseleave', (DomMouseEvent event) { final List pointerData = []; - final _SanitizedDetails? details = _sanitizer.sanitizeLeaveEvent(buttons: event.buttons!); + final _SanitizedDetails? details = _sanitizer.sanitizeLeaveEvent(buttons: event.buttons!.toInt()); if (details != null) { _convertEventsToPointerData(data: pointerData, event: event, details: details); _callback(pointerData); @@ -1027,7 +1028,7 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin { _addMouseEventListener(domWindow, 'mouseup', (DomMouseEvent event) { final List pointerData = []; - final _SanitizedDetails? sanitizedDetails = _sanitizer.sanitizeUpEvent(buttons: event.buttons); + final _SanitizedDetails? sanitizedDetails = _sanitizer.sanitizeUpEvent(buttons: event.buttons?.toInt()); if (sanitizedDetails != null) { _convertEventsToPointerData(data: pointerData, event: event, details: sanitizedDetails); _callback(pointerData); @@ -1056,8 +1057,8 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin { kind: ui.PointerDeviceKind.mouse, signalKind: ui.PointerSignalKind.none, device: _mouseDeviceId, - physicalX: event.clientX.toDouble() * ui.window.devicePixelRatio, - physicalY: event.clientY.toDouble() * ui.window.devicePixelRatio, + physicalX: event.clientX * ui.window.devicePixelRatio, + physicalY: event.clientY * ui.window.devicePixelRatio, buttons: details.buttons, pressure: 1.0, pressureMax: 1.0, diff --git a/lib/web_ui/lib/src/engine/safe_browser_api.dart b/lib/web_ui/lib/src/engine/safe_browser_api.dart index 9695f115476c8..77c2c9f8960c8 100644 --- a/lib/web_ui/lib/src/engine/safe_browser_api.dart +++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart @@ -195,8 +195,8 @@ DomCanvasElement? tryCreateCanvasElement(int width, int height) { return null; } try { - canvas.width = width; - canvas.height = height; + canvas.width = width.toDouble(); + canvas.height = height.toDouble(); } catch (e) { // It seems the tribal knowledge of why we anticipate an exception while // setting width/height on a non-null canvas and why it's OK to return null @@ -329,14 +329,14 @@ class DecodeOptions { class VideoFrame implements DomCanvasImageSource {} extension VideoFrameExtension on VideoFrame { - external int allocationSize(); + external double allocationSize(); external JsPromise copyTo(Uint8List destination); external String? get format; - external int get codedWidth; - external int get codedHeight; - external int get displayWidth; - external int get displayHeight; - external int? get duration; + external double get codedWidth; + external double get codedHeight; + external double get displayWidth; + external double get displayHeight; + external double? get duration; external VideoFrame clone(); external void close(); } @@ -367,8 +367,8 @@ extension ImageTrackListExtension on ImageTrackList { class ImageTrack {} extension ImageTrackExtension on ImageTrack { - external int get repetitionCount; - external int get frameCount; + external double get repetitionCount; + external double get frameCount; } void scaleCanvas2D(Object context2d, num x, num y) { @@ -983,11 +983,11 @@ class OffScreenCanvas { width = requestedWidth; height = requestedHeight; if(offScreenCanvas != null) { - offScreenCanvas!.width = requestedWidth; - offScreenCanvas!.height = requestedHeight; + offScreenCanvas!.width = requestedWidth.toDouble(); + offScreenCanvas!.height = requestedHeight.toDouble(); } else if (canvasElement != null) { - canvasElement!.width = requestedWidth; - canvasElement!.height = requestedHeight; + canvasElement!.width = requestedWidth.toDouble(); + canvasElement!.height = requestedHeight.toDouble(); _updateCanvasCssSize(canvasElement!); } } diff --git a/lib/web_ui/lib/src/engine/semantics/scrollable.dart b/lib/web_ui/lib/src/engine/semantics/scrollable.dart index 839a9c7bd5128..06910c7baaa76 100644 --- a/lib/web_ui/lib/src/engine/semantics/scrollable.dart +++ b/lib/web_ui/lib/src/engine/semantics/scrollable.dart @@ -131,10 +131,10 @@ class Scrollable extends RoleManager { /// The value of "scrollTop" or "scrollLeft", depending on the scroll axis. int get _domScrollPosition { if (semanticsObject.isVerticalScrollContainer) { - return semanticsObject.element.scrollTop; + return semanticsObject.element.scrollTop.toInt(); } else { assert(semanticsObject.isHorizontalScrollContainer); - return semanticsObject.element.scrollLeft; + return semanticsObject.element.scrollLeft.toInt(); } } @@ -167,9 +167,9 @@ class Scrollable extends RoleManager { ..width = '${rect.width.round()}px' ..height = '${canonicalNeutralScrollPosition}px'; - element.scrollTop = canonicalNeutralScrollPosition; + element.scrollTop = canonicalNeutralScrollPosition.toDouble(); // Read back because the effective value depends on the amount of content. - _effectiveNeutralScrollPosition = element.scrollTop; + _effectiveNeutralScrollPosition = element.scrollTop.toInt(); semanticsObject ..verticalContainerAdjustment = _effectiveNeutralScrollPosition.toDouble() @@ -184,9 +184,9 @@ class Scrollable extends RoleManager { ..width = '${canonicalNeutralScrollPosition}px' ..height = '${rect.height.round()}px'; - element.scrollLeft = canonicalNeutralScrollPosition; + element.scrollLeft = canonicalNeutralScrollPosition.toDouble(); // Read back because the effective value depends on the amount of content. - _effectiveNeutralScrollPosition = element.scrollLeft; + _effectiveNeutralScrollPosition = element.scrollLeft.toInt(); semanticsObject ..verticalContainerAdjustment = 0.0 ..horizontalContainerAdjustment = diff --git a/lib/web_ui/lib/src/engine/semantics/text_field.dart b/lib/web_ui/lib/src/engine/semantics/text_field.dart index a71f55b0085fa..290f82b6e5d06 100644 --- a/lib/web_ui/lib/src/engine/semantics/text_field.dart +++ b/lib/web_ui/lib/src/engine/semantics/text_field.dart @@ -288,24 +288,24 @@ class TextField extends RoleManager { _initializeForBlink(); return; } - num? lastTouchStartOffsetX; - num? lastTouchStartOffsetY; + num? lastPointerDownOffsetX; + num? lastPointerDownOffsetY; - editableElement.addEventListener('touchstart', + editableElement.addEventListener('pointerdown', allowInterop((DomEvent event) { - final DomTouchEvent touchEvent = event as DomTouchEvent; - lastTouchStartOffsetX = touchEvent.changedTouches!.last.clientX; - lastTouchStartOffsetY = touchEvent.changedTouches!.last.clientY; + final DomPointerEvent pointerEvent = event as DomPointerEvent; + lastPointerDownOffsetX = pointerEvent.clientX; + lastPointerDownOffsetY = pointerEvent.clientY; }), true); editableElement.addEventListener( - 'touchend', allowInterop((DomEvent event) { - final DomTouchEvent touchEvent = event as DomTouchEvent; + 'pointerup', allowInterop((DomEvent event) { + final DomPointerEvent pointerEvent = event as DomPointerEvent; - if (lastTouchStartOffsetX != null) { - assert(lastTouchStartOffsetY != null); - final num offsetX = touchEvent.changedTouches!.last.clientX; - final num offsetY = touchEvent.changedTouches!.last.clientY; + if (lastPointerDownOffsetX != null) { + assert(lastPointerDownOffsetY != null); + final num offsetX = pointerEvent.clientX - lastPointerDownOffsetX!; + final num offsetY = pointerEvent.clientY - lastPointerDownOffsetY!; // This should match the similar constant defined in: // @@ -318,13 +318,25 @@ class TextField extends RoleManager { // Recognize it as a tap that requires a keyboard. EnginePlatformDispatcher.instance.invokeOnSemanticsAction( semanticsObject.id, ui.SemanticsAction.tap, null); + + // We need to call focus for the following scenario: + // 1. The virtial keyboard in iOS gets dismissed by the 'Done' button + // located at the top right of the keyboard. + // 2. The user tries to focus on the input field again, either by + // VoiceOver or manually, but the keyboard does not show up. + // In this scenario, the Flutter framework does not send a semantic update, + // so we need to call focus after detecting a tap to make sure that the + // the virtual keyboard will show. + if (semanticsObject.hasFocus) { + editableElement.focus(); + } } } else { - assert(lastTouchStartOffsetY == null); + assert(lastPointerDownOffsetY == null); } - lastTouchStartOffsetX = null; - lastTouchStartOffsetY = null; + lastPointerDownOffsetX = null; + lastPointerDownOffsetY = null; }), true); } diff --git a/lib/web_ui/lib/src/engine/text/line_break_properties.dart b/lib/web_ui/lib/src/engine/text/line_break_properties.dart index 516471c32b09a..f3d89b8a016be 100644 --- a/lib/web_ui/lib/src/engine/text/line_break_properties.dart +++ b/lib/web_ui/lib/src/engine/text/line_break_properties.dart @@ -2,67 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// AUTO-GENERATED FILE. -// Generated by: tool/unicode_sync_script.dart -// -// Source: -// # LineBreak-13.0.0.txt -// # Date: 2020-02-17, 07:43:02 GMT [KW, LI] -// # © 2020 Unicode®, Inc. -// # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -// # For terms of use, see http://www.unicode.org/terms_of_use.html +import 'package:web_unicode/web_unicode.dart'; import 'unicode_range.dart'; -/// For an explanation of these enum values, see: -/// -/// * https://www.unicode.org/reports/tr14/tr14-45.html#DescriptionOfProperties -enum LineCharProperty { - CM, // serialized as "A" - BA, // serialized as "B" - LF, // serialized as "C" - // Normalized from: NL - BK, // serialized as "D" - CR, // serialized as "E" - SP, // serialized as "F" - EX, // serialized as "G" - QU, // serialized as "H" - // Normalized from: AI, SA, SG, XX - AL, // serialized as "I" - PR, // serialized as "J" - PO, // serialized as "K" - OP, // serialized as "L" - CP, // serialized as "M" - IS, // serialized as "N" - HY, // serialized as "O" - SY, // serialized as "P" - NU, // serialized as "Q" - CL, // serialized as "R" - GL, // serialized as "S" - BB, // serialized as "T" - HL, // serialized as "U" - JL, // serialized as "V" - JV, // serialized as "W" - JT, // serialized as "X" - // Normalized from: CJ - NS, // serialized as "Y" - ZW, // serialized as "Z" - ZWJ, // serialized as "a" - B2, // serialized as "b" - IN, // serialized as "c" - WJ, // serialized as "d" - ID, // serialized as "e" - EB, // serialized as "f" - H2, // serialized as "g" - H3, // serialized as "h" - CB, // serialized as "i" - RI, // serialized as "j" - EM, // serialized as "k" -} - -const String _packedLineBreakProperties = - '00000008A0009!B000a!C000b000cD000d!E000e000vA000w!F000x!G000y!H000z!I0010!J0011!K0012!I0013!H0014!L0015!M0016!I0017!J0018!N0019!O001a!N001b!P001c001lQ001m001nN001o001qI001r!G001s002iI002j!L002k!J002l!M002m003eI003f!L003g!B003h!R003i!I003j003oA003p!D003q004fA004g!S004h!L004i!K004j004lJ004m004qI004r!H004s!I004t!B004u004vI004w!K004x!J004y004zI0050!T00510056I0057!H0058005aI005b!L005c00jrI00js!T00jt00jvI00jw!T00jx00keI00kf!T00kg00lbI00lc00niA00nj!S00nk00nvA00nw00o2S00o300ofA00og00otI00ou!N00ov00w2I00w300w9A00wa013cI013d!N013e!B013h013iI013j!J013l014tA014u!B014v!A014w!I014x014yA014z!I01500151A0152!G0153!A015c0162U0167016aU016b016wI016x016zK01700171N01720173I0174017eA017f!G017g!A017i017jG017k018qI018r019bA019c019lQ019m!K019n019oQ019p019rI019s!A019t01cjI01ck!G01cl!I01cm01csA01ct01cuI01cv01d0A01d101d2I01d301d4A01d5!I01d601d9A01da01dbI01dc01dlQ01dm01e8I01e9!A01ea01f3I01f401fuA01fx01idI01ie01ioA01ip!I01j401jdQ01je01kaI01kb01kjA01kk01knI01ko!N01kp!G01kq!I01kt!A01ku01kvJ01kw01lhI01li01llA01lm!I01ln01lvA01lw!I01lx01lzA01m0!I01m101m5A01m801ncI01nd01nfA01ni01qfI01qr01r5A01r6!I01r701s3A01s401tlI01tm01toA01tp!I01tq01u7A01u8!I01u901ufA01ug01upI01uq01urA01us01utB01uu01v3Q01v401vkI01vl01vnA01vp01x5I01x8!A01x9!I01xa01xgA01xj01xkA01xn01xpA01xq!I01xz!A01y401y9I01ya01ybA01ye01ynQ01yo01ypI01yq01yrK01ys01ywI01yx!K01yy!I01yz!J01z001z1I01z2!A01z501z7A01z9020pI020s!A020u020yA02130214A02170219A021d!A021l021qI021y0227Q02280229A022a022cI022d!A022e!I022p022rA022t0249I024c!A024d!I024e024lA024n024pA024r024tA024w025dI025e025fA025i025rQ025s!I025t!J0261!I02620267A0269026bA026d027tI027w!A027x!I027y0284A02870288A028b028dA028l028nA028s028xI028y028zA0292029bQ029c029jI029u!A029v02bdI02bi02bmA02bq02bsA02bu02bxA02c0!I02c7!A02cm02cvQ02cw02d4I02d5!J02d6!I02dc02dgA02dh02f1I02f202f8A02fa02fcA02fe02fhA02fp02fqA02fs02g1I02g202g3A02g602gfQ02gn!T02go02gwI02gx02gzA02h0!T02h102ihI02ik!A02il!I02im02isA02iu02iwA02iy02j1A02j902jaA02ji02jlI02jm02jnA02jq02jzQ02k102k2I02kg02kjA02kk02m2I02m302m4A02m5!I02m602mcA02me02mgA02mi02mlA02mm02muI02mv!A02mw02n5I02n602n7A02na02njQ02nk02nsI02nt!K02nu02nzI02o102o3A02o502pyI02q2!A02q702qcA02qe!A02qg02qnA02qu02r3Q02r602r7A02r802t6I02tb!J02tc02trI02ts02u1Q02u202u3B02v502x9I02xc02xlQ02xo02yoI02yp02ysT02yt!I02yu02yvT02yw!S02yx02yyT02yz!B02z0!S02z102z5G02z6!S02z7!I02z8!G02z902zbI02zc02zdA02ze02zjI02zk02ztQ02zu0303I0304!B0305!A0306!I0307!A0308!I0309!A030a!L030b!R030c!L030d!R030e030fA030g031oI031t0326A0327!B0328032cA032d!B032e032fA032g032kI032l032vA032x033wA033y033zB03400345I0346!A0347034fI034g034hT034i!B034j!T034k034oI034p034qS035s037jI037k037tQ037u037vB037w039rI039s03a1Q03a203cvI03cw03fjV03fk03hjW03hk03jzX03k003tmI03tp03trA03ts!I03tt!B03tu03y5I03y8!B03y904fzI04g0!B04g104gqI04gr!L04gs!R04gw04iyI04iz04j1B04j204k1I04k204k4A04kg04kxI04ky04l0A04l104l2B04lc04ltI04lu04lvA04m804moI04mq04mrA04n404pfI04pg04phB04pi!Y04pj!I04pk!B04pl!I04pm!B04pn!J04po04ppI04ps04q1Q04q804qpI04qq04qrG04qs04qtB04qu!T04qv!I04qw04qxG04qy!I04qz04r1A04r2!S04r404rdQ04rk04ucI04ud04ueA04uf04vcI04vd!A04ve04ymI04yo04yzA04z404zfA04zk!I04zo04zpG04zq04zzQ0500053dI053k053tQ053u055iI055j055nA055q058cI058f!A058g058pQ058w0595Q059c059pI059s05a8A05c005c4A05c505dfI05dg05dwA05dx05e3I05e805ehQ05ei05ejB05ek!I05el05eoB05ep05eyI05ez05f7A05f805fgI05fk05fmA05fn05ggI05gh05gtA05gu05gvI05gw05h5Q05h605idI05ie05irA05j005k3I05k405knA05kr05kvB05kw05l5Q05l905lbI05lc05llQ05lm05mlI05mm05mnB05mo05onI05ow05oyA05oz!I05p005pkA05pl05poI05pp!A05pq05pvI05pw!A05px05pyI05pz05q1A05q205vjI05vk05x5A05x705xbA05xc06bgI06bh!T06bi!I06bk06bqB06br!S06bs06buB06bv!Z06bw!A06bx!a06by06bzA06c0!B06c1!S06c206c3B06c4!b06c506c7I06c806c9H06ca!L06cb06cdH06ce!L06cf!H06cg06cjI06ck06cmc06cn!B06co06cpD06cq06cuA06cv!S06cw06d3K06d4!I06d506d6H06d7!I06d806d9Y06da06dfI06dg!N06dh!L06di!R06dj06dlY06dm06dxI06dy!B06dz!I06e006e3B06e4!I06e506e7B06e8!d06e906ecI06ee06enA06eo06f0I06f1!L06f2!R06f306fgI06fh!L06fi!R06fk06fwI06g006g6J06g7!K06g806glJ06gm!K06gn06gqJ06gr!K06gs06gtJ06gu!K06gv06hbJ06hc06i8A06io06iqI06ir!K06is06iwI06ix!K06iy06j9I06ja!J06jb06q9I06qa06qbJ06qc06weI06wf!c06wg06x3I06x4!L06x5!R06x6!L06x7!R06x806xlI06xm06xne06xo06y0I06y1!L06y2!R06y3073jI073k073ne073o07i7I07i807ibe07ic07irI07is07ite07iu07ivI07iw!e07ix!I07iy07j0e07j1!f07j207j3e07j407jsI07jt07jve07jw07l3I07l4!e07l507lqI07lr!e07ls07ngI07nh07nse07nt07nwI07nx!e07ny!I07nz07o1e07o2!I07o307o4e07o507o7I07o807o9e07oa07obI07oc!e07od07oeI07of07ohe07oi07opI07oq!e07or07owI07ox07p1e07p2!I07p307p4e07p5!f07p6!e07p707p8I07p907pge07ph07pjI07pk07ple07pm07ppf07pq07ruI07rv07s0H07s1!I07s207s3G07s4!e07s507s7I07s8!L07s9!R07sa!L07sb!R07sc!L07sd!R07se!L07sf!R07sg!L07sh!R07si!L07sj!R07sk!L07sl!R07sm07usI07ut!L07uu!R07uv07vpI07vq!L07vr!R07vs!L07vt!R07vu!L07vv!R07vw!L07vx!R07vy!L07vz!R07w00876I0877!L0878!R0879!L087a!R087b!L087c!R087d!L087e!R087f!L087g!R087h!L087i!R087j!L087k!R087l!L087m!R087n!L087o!R087p!L087q!R087r!L087s!R087t089jI089k!L089l!R089m!L089n!R089o08ajI08ak!L08al!R08am08viI08vj08vlA08vm08vnI08vt!G08vu08vwB08vx!I08vy!G08vz!B08w008z3I08z4!B08zj!A08zk0926I09280933A0934093hH093i093pB093q!I093r!B093s!L093t!B093u093vI093w093xH093y093zI09400941H0942!L0943!R0944!L0945!R0946!L0947!R0948!L0949!R094a094dB094e!G094f!I094g094hB094i!I094j094kB094l094pI094q094rb094s094uB094v!I094w094xB094y!L094z0956B0957!I0958!B0959!I095a095bB095c095eI096o097de097f099ve09a809g5e09gw09h7e09hc!B09hd09heR09hf09hge09hh!Y09hi09hje09hk!L09hl!R09hm!L09hn!R09ho!L09hp!R09hq!L09hr!R09hs!L09ht!R09hu09hve09hw!L09hx!R09hy!L09hz!R09i0!L09i1!R09i2!L09i3!R09i4!Y09i5!L09i609i7R09i809ihe09ii09inA09io09ise09it!A09iu09iye09iz09j0Y09j109j3e09j5!Y09j6!e09j7!Y09j8!e09j9!Y09ja!e09jb!Y09jc!e09jd!Y09je09k2e09k3!Y09k409kye09kz!Y09l0!e09l1!Y09l2!e09l3!Y09l409l9e09la!Y09lb09lge09lh09liY09ll09lmA09ln09lqY09lr!e09ls09ltY09lu!e09lv!Y09lw!e09lx!Y09ly!e09lz!Y09m0!e09m1!Y09m209mqe09mr!Y09ms09nme09nn!Y09no!e09np!Y09nq!e09nr!Y09ns09nxe09ny!Y09nz09o4e09o509o6Y09o709oae09ob09oeY09of!e09ol09pre09pt09see09sg09ure09v409vjY09vk09wee09wg09xje09xk09xrI09xs0fcve0fcw0fenI0feo0vmce0vmd!Y0vme0wi4e0wi80wjqe0wk00wl9I0wla0wlbB0wlc0wssI0wst!B0wsu!G0wsv!B0wsw0wtbI0wtc0wtlQ0wtm0wviI0wvj0wvmA0wvn!I0wvo0wvxA0wvy0wwtI0wwu0wwvA0www0wz3I0wz40wz5A0wz6!I0wz70wzbB0wzk0x6pI0x6q!A0x6r0x6tI0x6u!A0x6v0x6yI0x6z!A0x700x7mI0x7n0x7rA0x7s0x7vI0x7w!A0x800x87I0x88!K0x890x9vI0x9w0x9xT0x9y0x9zG0xa80xa9A0xaa0xbnI0xbo0xc5A0xce0xcfB0xcg0xcpQ0xcw0xddA0xde0xdnI0xdo!T0xdp0xdqI0xdr!A0xds0xe1Q0xe20xetI0xeu0xf1A0xf20xf3B0xf40xfqI0xfr0xg3A0xgf!I0xgg0xh8V0xhc0xhfA0xhg0xiqI0xir0xj4A0xj50xjaI0xjb0xjdB0xje0xjjI0xjk0xjtQ0xjy0xkfI0xkg0xkpQ0xkq0xm0I0xm10xmeA0xmo0xmqI0xmr!A0xms0xmzI0xn00xn1A0xn40xndQ0xng!I0xnh0xnjB0xnk0xreI0xrf0xrjA0xrk0xrlB0xrm0xroI0xrp0xrqA0xs10xyaI0xyb0xyiA0xyj!B0xyk0xylA0xyo0xyxQ0xz4!g0xz50xzvh0xzw!g0xzx0y0nh0y0o!g0y0p0y1fh0y1g!g0y1h0y27h0y28!g0y290y2zh0y30!g0y310y3rh0y3s!g0y3t0y4jh0y4k!g0y4l0y5bh0y5c!g0y5d0y63h0y64!g0y650y6vh0y6w!g0y6x0y7nh0y7o!g0y7p0y8fh0y8g!g0y8h0y97h0y98!g0y990y9zh0ya0!g0ya10yarh0yas!g0yat0ybjh0ybk!g0ybl0ycbh0ycc!g0ycd0yd3h0yd4!g0yd50ydvh0ydw!g0ydx0yenh0yeo!g0yep0yffh0yfg!g0yfh0yg7h0yg8!g0yg90ygzh0yh0!g0yh10yhrh0yhs!g0yht0yijh0yik!g0yil0yjbh0yjc!g0yjd0yk3h0yk4!g0yk50ykvh0ykw!g0ykx0ylnh0ylo!g0ylp0ymfh0ymg!g0ymh0yn7h0yn8!g0yn90ynzh0yo0!g0yo10yorh0yos!g0yot0ypjh0ypk!g0ypl0yqbh0yqc!g0yqd0yr3h0yr4!g0yr50yrvh0yrw!g0yrx0ysnh0yso!g0ysp0ytfh0ytg!g0yth0yu7h0yu8!g0yu90yuzh0yv0!g0yv10yvrh0yvs!g0yvt0ywjh0ywk!g0ywl0yxbh0yxc!g0yxd0yy3h0yy4!g0yy50yyvh0yyw!g0yyx0yznh0yzo!g0yzp0z0fh0z0g!g0z0h0z17h0z18!g0z190z1zh0z20!g0z210z2rh0z2s!g0z2t0z3jh0z3k!g0z3l0z4bh0z4c!g0z4d0z53h0z54!g0z550z5vh0z5w!g0z5x0z6nh0z6o!g0z6p0z7fh0z7g!g0z7h0z87h0z88!g0z890z8zh0z90!g0z910z9rh0z9s!g0z9t0zajh0zak!g0zal0zbbh0zbc!g0zbd0zc3h0zc4!g0zc50zcvh0zcw!g0zcx0zdnh0zdo!g0zdp0zefh0zeg!g0zeh0zf7h0zf8!g0zf90zfzh0zg0!g0zg10zgrh0zgs!g0zgt0zhjh0zhk!g0zhl0zibh0zic!g0zid0zj3h0zj4!g0zj50zjvh0zjw!g0zjx0zknh0zko!g0zkp0zlfh0zlg!g0zlh0zm7h0zm8!g0zm90zmzh0zn0!g0zn10znrh0zns!g0znt0zojh0zok!g0zol0zpbh0zpc!g0zpd0zq3h0zq4!g0zq50zqvh0zqw!g0zqx0zrnh0zro!g0zrp0zsfh0zsg!g0zsh0zt7h0zt8!g0zt90ztzh0zu0!g0zu10zurh0zus!g0zut0zvjh0zvk!g0zvl0zwbh0zwc!g0zwd0zx3h0zx4!g0zx50zxvh0zxw!g0zxx0zynh0zyo!g0zyp0zzfh0zzg!g0zzh1007h1008!g1009100zh1010!g1011101rh101s!g101t102jh102k!g102l103bh103c!g103d1043h1044!g1045104vh104w!g104x105nh105o!g105p106fh106g!g106h1077h1078!g1079107zh1080!g1081108rh108s!g108t109jh109k!g109l10abh10ac!g10ad10b3h10b4!g10b510bvh10bw!g10bx10cnh10co!g10cp10dfh10dg!g10dh10e7h10e8!g10e910ezh10f0!g10f110frh10fs!g10ft10gjh10gk!g10gl10hbh10hc!g10hd10i3h10i4!g10i510ivh10iw!g10ix10jnh10jo!g10jp10kfh10kg!g10kh10l7h10l8!g10l910lzh10m0!g10m110mrh10ms!g10mt10njh10nk!g10nl10obh10oc!g10od10p3h10p4!g10p510pvh10pw!g10px10qnh10qo!g10qp10rfh10rg!g10rh10s7h10s8!g10s910szh10t0!g10t110trh10ts!g10tt10ujh10uk!g10ul10vbh10vc!g10vd10w3h10w4!g10w510wvh10ww!g10wx10xnh10xo!g10xp10yfh10yg!g10yh10z7h10z8!g10z910zzh1100!g1101110rh110s!g110t111jh111k!g111l112bh112c!g112d1133h1134!g1135113vh113w!g113x114nh114o!g114p115fh115g!g115h1167h1168!g1169116zh1170!g1171117rh117s!g117t118jh118k!g118l119bh119c!g119d11a3h11a4!g11a511avh11aw!g11ax11bnh11bo!g11bp11cfh11cg!g11ch11d7h11d8!g11d911dzh11e0!g11e111erh11es!g11et11fjh11fk!g11fl11gbh11gc!g11gd11h3h11h4!g11h511hvh11hw!g11hx11inh11io!g11ip11jfh11jg!g11jh11k7h11k8!g11k911kzh11l0!g11l111lrh11ls!g11lt11mjh11mk!g11ml11nbh11nc!g11nd11o3h11o4!g11o511ovh11ow!g11ox11pnh11po!g11pp11qfh11qg!g11qh11r7h11r8!g11r911rzh11s0!g11s111srh11ss!g11st11tjh11tk!g11tl11ubh11uc!g11ud11v3h11v4!g11v511vvh11vw!g11vx11wnh11wo!g11wp11xfh11xg!g11xh11y7h11y8!g11y911yzh11z0!g11z111zrh11zs!g11zt120jh120k!g120l121bh121c!g121d1223h1224!g1225122vh122w!g122x123nh123o!g123p124fh124g!g124h1257h1258!g1259125zh1260!g1261126rh126s!g126t127jh127k!g127l128bh128c!g128d1293h1294!g1295129vh129w!g129x12anh12ao!g12ap12bfh12bg!g12bh12c7h12c8!g12c912czh12d0!g12d112drh12ds!g12dt12ejh12ek!g12el12fbh12fc!g12fd12g3h12g4!g12g512gvh12gw!g12gx12hnh12ho!g12hp12ifh12ig!g12ih12j7h12j8!g12j912jzh12k0!g12k112krh12ks!g12kt12ljh12lk!g12ll12mbh12mc!g12md12n3h12n4!g12n512nvh12nw!g12nx12onh12oo!g12op12pfh12pg!g12ph12q7h12q8!g12q912qzh12r0!g12r112rrh12rs!g12rt12sjh12sk!g12sl12tbh12tc!g12td12u3h12u4!g12u512uvh12uw!g12ux12vnh12vo!g12vp12wfh12wg!g12wh12x7h12x8!g12x912xzh12y0!g12y112yrh12ys!g12yt12zjh12zk!g12zl130bh130c!g130d1313h1314!g1315131vh131w!g131x132nh132o!g132p133fh133g!g133h1347h1348!g1349134zh1350!g1351135rh135s!g135t136jh136k!g136l137bh137c!g137d1383h1384!g1385138vh138w!g138x139nh139o!g139p13afh13ag!g13ah13b7h13b8!g13b913bzh13c0!g13c113crh13cs!g13ct13djh13dk!g13dl13ebh13ec!g13ed13f3h13f4!g13f513fvh13fw!g13fx13gnh13go!g13gp13hfh13hg!g13hh13i7h13i8!g13i913izh13j0!g13j113jrh13js!g13jt13kjh13kk!g13kl13lbh13lc!g13ld13m3h13m4!g13m513mvh13mw!g13mx13nnh13no!g13np13ofh13og!g13oh13p7h13p8!g13p913pzh13q0!g13q113qrh13qs!g13qt13rjh13rk!g13rl13sbh13sc!g13sd13t3h13t4!g13t513tvh13tw!g13tx13unh13uo!g13up13vfh13vg!g13vh13w7h13w8!g13w913wzh13x0!g13x113xrh13xs!g13xt13yjh13yk!g13yl13zbh13zc!g13zd1403h1404!g1405140vh140w!g140x141nh141o!g141p142fh142g!g142h1437h1438!g1439143zh1440!g1441144rh144s!g144t145jh145k!g145l146bh146c!g146d1473h1474!g1475147vh147w!g147x148nh148o!g148p149fh149g!g149h14a7h14a8!g14a914azh14b0!g14b114brh14bs!g14bt14cjh14ck!g14cl14dbh14dc!g14dd14e3h14e4!g14e514evh14ew!g14ex14fnh14fo!g14fp14gfh14gg!g14gh14h7h14h8!g14h914hzh14i0!g14i114irh14is!g14it14jjh14jk!g14jl14kbh14kc!g14kd14l3h14l4!g14l514lvh14lw!g14lx14mnh14mo!g14mp14nfh14ng!g14nh14o7h14o8!g14o914ozh14p0!g14p114prh14ps!g14pt14qjh14qk!g14ql14rbh14rc!g14rd14s3h14s4!g14s514svh14sw!g14sx14tnh14to!g14tp14ufh14ug!g14uh14v7h14v8!g14v914vzh14w0!g14w114wrh14ws!g14wt14xjh14xk!g14xl14ybh14yc!g14yd14z3h14z4!g14z514zvh14zw!g14zx150nh150o!g150p151fh151g!g151h1527h1528!g1529152zh1530!g1531153rh153s!g153t154jh154k!g154l155bh155c!g155d1563h1564!g1565156vh156w!g156x157nh157o!g157p158fh158g!g158h1597h1598!g1599159zh15a0!g15a115arh15as!g15at15bjh15bk!g15bl15cbh15cc!g15cd15d3h15d4!g15d515dvh15dw!g15dx15enh15eo!g15ep15ffh15fg!g15fh15g7h15g8!g15g915gzh15h0!g15h115hrh15hs!g15ht15ijh15ik!g15il15jbh15jc!g15jd15k3h15k4!g15k515kvh15kw!g15kx15lnh15lo!g15lp15mfh15mg!g15mh15n7h15n8!g15n915nzh15o0!g15o115orh15os!g15ot15pjh15pk!g15pl15qbh15qc!g15qd15r3h15r4!g15r515rvh15rw!g15rx15snh15so!g15sp15tfh15tg!g15th15u7h15u8!g15u915uzh15v0!g15v115vrh15vs!g15vt15wjh15wk!g15wl15xbh15xc!g15xd15y3h15y4!g15y515yvh15yw!g15yx15znh15zo!g15zp160fh160g!g160h1617h1618!g1619161zh1620!g1621162rh162s!g162t163jh163k!g163l164bh164c!g164d1653h1654!g1655165vh165w!g165x166nh166o!g166p167fh167g!g167h1687h1688!g1689168zh1690!g1691169rh169s!g169t16ajh16ak!g16al16bbh16bc!g16bd16c3h16c4!g16c516cvh16cw!g16cx16dnh16do!g16dp16efh16eg!g16eh16f7h16f8!g16f916fzh16g0!g16g116grh16gs!g16gt16hjh16hk!g16hl16ibh16ic!g16id16j3h16j4!g16j516jvh16jw!g16jx16knh16ko!g16kp16lfh16ls16meW16mj16nvX16o01d6nI1d6o1dkve1dkw1dljI1dlp!U1dlq!A1dlr1dm0U1dm1!I1dm21dmeU1dmg1dmkU1dmm!U1dmo1dmpU1dmr1dmsU1dmu1dn3U1dn41e0tI1e0u!R1e0v!L1e1c1e63I1e64!K1e65!I1e681e6nA1e6o!N1e6p1e6qR1e6r1e6sN1e6t1e6uG1e6v!L1e6w!R1e6x!c1e741e7jA1e7k1e7oe1e7p!L1e7q!R1e7r!L1e7s!R1e7t!L1e7u!R1e7v!L1e7w!R1e7x!L1e7y!R1e7z!L1e80!R1e81!L1e82!R1e83!L1e84!R1e851e86e1e87!L1e88!R1e891e8fe1e8g!R1e8h!e1e8i!R1e8k1e8lY1e8m1e8nG1e8o!e1e8p!L1e8q!R1e8r!L1e8s!R1e8t!L1e8u!R1e8v1e92e1e94!e1e95!J1e96!K1e97!e1e9c1ed8I1edb!d1edd!G1ede1edfe1edg!J1edh!K1edi1edje1edk!L1edl!R1edm1edne1edo!R1edp!e1edq!R1edr1ee1e1ee21ee3Y1ee41ee6e1ee7!G1ee81eeye1eez!L1ef0!e1ef1!R1ef21efue1efv!L1efw!e1efx!R1efy!e1efz!L1eg01eg1R1eg2!L1eg31eg4R1eg5!Y1eg6!e1eg71eggY1egh1ehpe1ehq1ehrY1ehs1eime1eiq1eive1eiy1ej3e1ej61ejbe1eje1ejge1ejk!K1ejl!J1ejm1ejoe1ejp1ejqJ1ejs1ejyI1ek91ekbA1ekc!i1ekd1ereI1erk1ermB1err1eykI1eyl!A1f281f4gI1f4w!A1f4x1f91I1f921f96A1f9c1fa5I1fa7!B1fa81fbjI1fbk!B1fbl1fh9I1fhc1fhlQ1fhs1g7pI1g7r!B1g7s1gd7I1gdb!B1gdc1gjkI1gjl1gjnA1gjp1gjqA1gjw1gjzA1gk01gl1I1gl41gl6A1glb!A1glc1glkI1gls1glzB1gm01gpwI1gpx1gpyA1gq31gq7I1gq81gqdB1gqe!c1gqo1gs5I1gs91gsfB1gsg1h5vI1h5w1h5zA1h681h6hQ1heo1hgpI1hgr1hgsA1hgt!B1hgw1hl1I1hl21hlcA1hld1hpyI1hq81hqaA1hqb1hrrI1hrs1hs6A1hs71hs8B1hs91ht1I1ht21htbQ1htr1htuA1htv1hv3I1hv41hveA1hvf1hvhI1hvi1hvlB1hvx1hwoI1hww1hx5Q1hxc1hxeA1hxf1hyeI1hyf1hysA1hyu1hz3Q1hz41hz7B1hz8!I1hz91hzaA1hzb1i0iI1i0j!A1i0k!I1i0l!T1i0m!I1i0w1i0yA1i0z1i2aI1i2b1i2oA1i2p1i2sI1i2t1i2uB1i2v!I1i2w!B1i2x1i30A1i31!I1i321i33A1i341i3dQ1i3e!I1i3f!T1i3g!I1i3h1i3jB1i3l1i5nI1i5o1i5zA1i601i61B1i62!I1i631i64B1i65!I1i66!A1i801i94I1i95!B1i9c1iamI1ian1iayA1ib41ibdQ1ibk1ibnA1ibp1id5I1id71id8A1id9!I1ida1idgA1idj1idkA1idn1idpA1ids!I1idz!A1ie51ie9I1iea1iebA1iee1iekA1ieo1iesA1iio1ik4I1ik51ikmA1ikn1ikqI1ikr1ikuB1ikv!I1ikw1il5Q1il61il7B1il9!I1ila!A1ilb1injI1ink1io3A1io41io7I1iog1iopQ1itc1iumI1iun1iutA1iuw1iv4A1iv5!T1iv61iv7B1iv81iv9G1iva1ivcI1ivd1ivrB1ivs1ivvI1ivw1ivxA1iww1iy7I1iy81iyoA1iyp1iyqB1iyr1iysI1iz41izdQ1izk1izwT1j0g1j1mI1j1n1j1zA1j20!I1j281j2hQ1j401j57I1j5c1j5lQ1j5m1j5nI1j5o1j5qB1j5r1jcbI1jcc1jcqA1jcr1jhbI1jhc1jhlQ1jhm1jjjI1jjk1jjpA1jjr1jjsA1jjv1jjyA1jjz!I1jk0!A1jk1!I1jk21jk3A1jk41jk6B1jkg1jkpQ1jmo1jo0I1jo11jo7A1joa1jogA1joh!I1joi!T1joj!I1jok!A1jpc!I1jpd1jpmA1jpn1jqqI1jqr1jqxA1jqy!I1jqz1jr2A1jr3!T1jr4!I1jr51jr8B1jr9!T1jra!I1jrb!A1jrk!I1jrl1jrvA1jrw1jt5I1jt61jtlA1jtm1jtoB1jtp!I1jtq1jtsT1jtt1jtuB1juo1k4uI1k4v1k52A1k541k5bA1k5c!I1k5d1k5hB1k5s1k61Q1k621k6kI1k6o!T1k6p!G1k6q1k7jI1k7m1k87A1k891k8mA1kao1kc0I1kc11kc6A1kca!A1kcc1kcdA1kcf1kclA1kcm!I1kcn!A1kcw1kd5Q1kdc1kehI1kei1kemA1keo1kepA1ker1kevA1kew!I1kf41kfdQ1ko01koiI1koj1komA1kon1kv0I1kv11kv4K1kv51kvlI1kvz!B1kw01lriI1lrk1lroB1ls01oifI1oig1oiiL1oij1oilR1oim1ojlI1ojm!R1ojn1ojpI1ojq!L1ojr!R1ojs!L1ojt!R1oju1oqgI1oqh!L1oqi1oqjR1oqk1oviI1ovk1ovqS1ovr!L1ovs!R1s001sctI1scu!L1scv!R1scw1zkuI1zkw1zl5Q1zla1zlbB1zo01zotI1zow1zp0A1zp1!B1zpc1zqnI1zqo1zquA1zqv1zqxB1zqy1zr7I1zr8!B1zr9!I1zrk1zrtQ1zrv20euI20ev20ewB20ex20juI20jz!A20k0!I20k120ljA20lr20luA20lv20m7I20o020o3Y20o4!S20og20ohA20ow25fbe25fk260ve260w26dxI26f426fce2dc02djye2dlc2dleY2dlw2dlzY2dm82dx7e2fpc2ftoI2ftp2ftqA2ftr!B2fts2ftvA2jnk2jxgI2jxh2jxlA2jxm2jxoI2jxp2jyaA2jyb2jycI2jyd2jyjA2jyk2jzdI2jze2jzhA2jzi2k3lI2k3m2k3oA2k3p2l6zI2l722l8fQ2l8g2lmnI2lmo2lo6A2lo72loaI2lob2lpoA2lpp2lpwI2lpx!A2lpy2lqbI2lqc!A2lqd2lqeI2lqf2lqiB2lqj!I2lqz2lr3A2lr52lrjA2mtc2mtiA2mtk2mu0A2mu32mu9A2mub2mucA2mue2muiA2n0g2n1oI2n1s2n1yA2n1z2n25I2n282n2hQ2n2m2ne3I2ne42ne7A2ne82nehQ2nen!J2oe82ojzI2ok02ok6A2olc2on7I2on82oneA2onf!I2onk2ontQ2ony2onzL2p9t2pbfI2pbg!K2pbh2pbjI2pbk!K2pbl2prlI2pz42q67e2q682q6kI2q6l2q6ne2q6o2q98I2q992q9be2q9c2qb0I2qb12qcle2qcm2qdbj2qdc2qo4e2qo5!f2qo62qore2qos2qotI2qou2qpge2qph2qpiI2qpj2qpne2qpo!I2qpp2qpte2qpu2qpwf2qpx2qpye2qpz!f2qq02qq1e2qq22qq4f2qq52qree2qrf2qrjk2qrk2qtde2qte2qtff2qtg2qthe2qti2qtsf2qtt2qude2que2quwf2qux2quze2qv0!f2qv12qv4e2qv52qv7f2qv8!e2qv92qvbf2qvc2qvie2qvj!f2qvk!e2qvl!f2qvm2qvze2qw0!I2qw1!e2qw2!I2qw3!e2qw4!I2qw52qw9e2qwa!f2qwb2qwee2qwf!I2qwg!e2qwh2qwiI2qwj2qyne2qyo2qyuI2qyv2qzae2qzb2qzoI2qzp2r01e2r022r0pI2r0q2r1ve2r1w2r1xf2r1y2r21e2r22!f2r232r2ne2r2o!f2r2p2r2se2r2t2r2uf2r2v2r4je2r4k2r4rI2r4s2r5fe2r5g2r5lI2r5m2r7oe2r7p2r7rf2r7s2r7ue2r7v2r7zf2r802r91I2r922r94H2r952r97Y2r982r9bI2r9c2raae2rab!f2rac2rare2ras2rauf2rav2rb3e2rb4!f2rb52rbfe2rbg!f2rbh2rcve2rcw2rg3I2rg42rgfe2rgg2risI2rit2rjze2rk02rkbI2rkc2rkfe2rkg2rlzI2rm02rm7e2rm82rmhI2rmi2rmne2rmo2rnrI2rns2rnze2ro02rotI2rou2rr3e2rr42rrfI2rrg!f2rrh2rrie2rrj!f2rrk2rrre2rrs2rrzf2rs02rs5e2rs6!f2rs72rsfe2rsg2rspf2rsq2rsre2rss2rsuf2rsv2ruee2ruf!f2rug2rw4e2rw52rw6f2rw7!e2rw82rw9f2rwa!e2rwb!f2rwc2rwse2rwt2rwvf2rww!e2rwx2rx9f2rxa2ry7e2ry82s0jI2s0k2s5be2s5c2sayI2sc02sc9Q2scg2t4te2t4w47p9e47pc5m9pejny9!Ajnz4jo1rAjo5cjobzAl2ionvnhI'; - +export 'package:web_unicode/web_unicode.dart' show LineCharProperty; UnicodePropertyLookup get lineLookup => ensureLineLookupInitialized(); @@ -75,10 +19,10 @@ UnicodePropertyLookup get lineLookup => ensureLineLookupInitia UnicodePropertyLookup ensureLineLookupInitialized() { return _lineLookup ??= UnicodePropertyLookup.fromPackedData( - _packedLineBreakProperties, - 937, + packedLineBreakProperties, + singleLineBreakRangesCount, LineCharProperty.values, - LineCharProperty.AL, + defaultLineCharProperty, ); } diff --git a/lib/web_ui/lib/src/engine/text/line_breaker.dart b/lib/web_ui/lib/src/engine/text/line_breaker.dart index 5c30f81ce95c9..c2bf0ab1e2090 100644 --- a/lib/web_ui/lib/src/engine/text/line_breaker.dart +++ b/lib/web_ui/lib/src/engine/text/line_breaker.dart @@ -80,7 +80,7 @@ class V8LineBreakFragmenter extends TextFragmenter implements LineBreakFragmente while (iterator.next() != -1) { final LineBreakType type = _getBreakType(iterator); - final int fragmentEnd = iterator.current(); + final int fragmentEnd = iterator.current().toInt(); int trailingNewlines = 0; int trailingSpaces = 0; @@ -128,7 +128,7 @@ class V8LineBreakFragmenter extends TextFragmenter implements LineBreakFragmente /// Gets break type from v8BreakIterator. LineBreakType _getBreakType(DomV8BreakIterator iterator) { - final int fragmentEnd = iterator.current(); + final int fragmentEnd = iterator.current().toInt(); // I don't know why v8BreakIterator uses the type "none" to mean "soft break". if (iterator.breakType() != 'none') { diff --git a/lib/web_ui/lib/src/engine/text/measurement.dart b/lib/web_ui/lib/src/engine/text/measurement.dart index 6eb95a971575d..0a8ccddfe16e1 100644 --- a/lib/web_ui/lib/src/engine/text/measurement.dart +++ b/lib/web_ui/lib/src/engine/text/measurement.dart @@ -102,7 +102,7 @@ double measureSubstring( } else { final String sub = start == 0 && end == text.length ? text : text.substring(start, end); - width = canvasContext.measureText(sub).width!.toDouble(); + width = canvasContext.measureText(sub).width!; } _lastStart = start; diff --git a/lib/web_ui/lib/src/engine/text/ruler.dart b/lib/web_ui/lib/src/engine/text/ruler.dart index 18c2d80821e91..bce0e6bbd08ff 100644 --- a/lib/web_ui/lib/src/engine/text/ruler.dart +++ b/lib/web_ui/lib/src/engine/text/ruler.dart @@ -137,7 +137,7 @@ class TextDimensions { /// The height of the paragraph being measured. double get height { - double cachedHeight = _readAndCacheMetrics().height as double; + double cachedHeight = _readAndCacheMetrics().height; if (browserEngine == BrowserEngine.firefox && // In the flutter tester environment, we use a predictable-size for font // measurement tests. @@ -170,7 +170,7 @@ class TextHeightRuler { final TextDimensions _dimensions = TextDimensions(domDocument.createElement('flt-paragraph')); /// The alphabetic baseline for this ruler's [textHeightStyle]. - late final double alphabeticBaseline = _probe.getBoundingClientRect().bottom.toDouble(); + late final double alphabeticBaseline = _probe.getBoundingClientRect().bottom; /// The height for this ruler's [textHeightStyle]. late final double height = _dimensions.height; diff --git a/lib/web_ui/lib/src/engine/text/word_break_properties.dart b/lib/web_ui/lib/src/engine/text/word_break_properties.dart index 6c94e513ece2e..4b1ed77b137e5 100644 --- a/lib/web_ui/lib/src/engine/text/word_break_properties.dart +++ b/lib/web_ui/lib/src/engine/text/word_break_properties.dart @@ -2,51 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// AUTO-GENERATED FILE. -// Generated by: tool/unicode_sync_script.dart -// -// Source: -// # WordBreakProperty-13.0.0.txt -// # Date: 2020-01-22, 00:07:44 GMT -// # © 2020 Unicode®, Inc. -// # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -// # For terms of use, see http://www.unicode.org/terms_of_use.html +import 'package:web_unicode/web_unicode.dart'; import 'unicode_range.dart'; -/// For an explanation of these enum values, see: -/// -/// * http://unicode.org/reports/tr29/#Table_Word_Break_Property_Values -enum WordCharProperty { - DoubleQuote, // serialized as "A" - SingleQuote, // serialized as "B" - HebrewLetter, // serialized as "C" - CR, // serialized as "D" - LF, // serialized as "E" - Newline, // serialized as "F" - Extend, // serialized as "G" - RegionalIndicator, // serialized as "H" - Format, // serialized as "I" - Katakana, // serialized as "J" - ALetter, // serialized as "K" - MidLetter, // serialized as "L" - MidNum, // serialized as "M" - MidNumLet, // serialized as "N" - Numeric, // serialized as "O" - ExtendNumLet, // serialized as "P" - ZWJ, // serialized as "Q" - WSegSpace, // serialized as "R" - Unknown, // serialized as "S" -} - -const String _packedWordBreakProperties = - '000a!E000b000cF000d!D000w!R000y!A0013!B0018!M001a!N001c001lO001m!L001n!M001t002iK002n!P002p003eK003p!F004q!K004t!I0051!K0053!L0056!K005c005yK0060006uK006w00k7K00ke00lbK00lc00ofG00og00okK00om00onK00oq00otK00ou!M00ov!K00p2!K00p3!L00p400p6K00p8!K00pa00ptK00pv00s5K00s700w1K00w300w9G00wa010vK010x011yK01210124K0126!K0127!L0128013cK013d!M013e!K013l014tG014v!G014x014yG01500151G0153!G015c0162C0167016aC016b!K016c!L016o016tI01700171M0174017eG017g!I017k018qK018r019bG019c019lO019n!O019o!M019q019rK019s!G019t01cjK01cl!K01cm01csG01ct!I01cv01d0G01d101d2K01d301d4G01d601d9G01da01dbK01dc01dlO01dm01doK01dr!K01e7!I01e8!K01e9!G01ea01f3K01f401fuG01fx01idK01ie01ioG01ip!K01j401jdO01je01kaK01kb01kjG01kk01klK01ko!M01kq!K01kt!G01kw01lhK01li01llG01lm!K01ln01lvG01lw!K01lx01lzG01m0!K01m101m5G01mo01ncK01nd01nfG01nk01nuK01pc01pwK01py01qfK01qr01r5G01r6!I01r701s3G01s401tlK01tm01toG01tp!K01tq01u7G01u8!K01u901ufG01ug01upK01uq01urG01uu01v3O01v501vkK01vl01vnG01vp01vwK01vz01w0K01w301woK01wq01wwK01wy!K01x201x5K01x8!G01x9!K01xa01xgG01xj01xkG01xn01xpG01xq!K01xz!G01y401y5K01y701y9K01ya01ybG01ye01ynO01yo01ypK01z0!K01z2!G01z501z7G01z901zeK01zj01zkK01zn0208K020a020gK020i020jK020l020mK020o020pK020s!G020u020yG02130214G02170219G021d!G021l021oK021q!K021y0227O02280229G022a022cK022d!G022p022rG022t0231K02330235K0237023sK023u0240K02420243K02450249K024c!G024d!K024e024lG024n024pG024r024tG024w!K025c025dK025e025fG025i025rO0261!K02620267G0269026bG026d026kK026n026oK026r027cK027e027kK027m027nK027p027tK027w!G027x!K027y0284G02870288G028b028dG028l028nG028s028tK028v028xK028y028zG0292029bO029d!K029u!G029v!K029x02a2K02a602a8K02aa02adK02ah02aiK02ak!K02am02anK02ar02asK02aw02ayK02b202bdK02bi02bmG02bq02bsG02bu02bxG02c0!K02c7!G02cm02cvO02dc02dgG02dh02doK02dq02dsK02du02egK02ei02exK02f1!K02f202f8G02fa02fcG02fe02fhG02fp02fqG02fs02fuK02g002g1K02g202g3G02g602gfO02gw!K02gx02gzG02h102h8K02ha02hcK02he02i0K02i202ibK02id02ihK02ik!G02il!K02im02isG02iu02iwG02iy02j1G02j902jaG02ji!K02jk02jlK02jm02jnG02jq02jzO02k102k2K02kg02kjG02kk02ksK02ku02kwK02ky02m2K02m302m4G02m5!K02m602mcG02me02mgG02mi02mlG02mm!K02ms02muK02mv!G02n302n5K02n602n7G02na02njO02nu02nzK02o102o3G02o502omK02oq02pdK02pf02pnK02pp!K02ps02pyK02q2!G02q702qcG02qe!G02qg02qnG02qu02r3O02r602r7G02sx!G02t002t6G02tj02tqG02ts02u1O02wh!G02wk02wsG02x402x9G02xc02xlO02yo!K02zc02zdG02zk02ztO0305!G0307!G0309!G030e030fG030g030nK030p031oK031t032cG032e032fG032g032kK032l032vG032x033wG0346!G036z037iG037k037tO03860389G038e038gG038i038kG038n038tG038x0390G039e039pG039r!G039s03a1O03a203a5G03a803b9K03bb!K03bh!K03bk03cqK03cs03m0K03m203m5K03m803meK03mg!K03mi03mlK03mo03nsK03nu03nxK03o003owK03oy03p1K03p403paK03pc!K03pe03phK03pk03pyK03q003rkK03rm03rpK03rs03tmK03tp03trG03uo03v3K03vk03xxK03y003y5K03y904fgK04fj04fzK04g0!R04g104gqK04gw04iyK04j204jcK04jk04jwK04jy04k1K04k204k4G04kg04kxK04ky04l0G04lc04ltK04lu04lvG04m804mkK04mm04moK04mq04mrG04ok04pfG04pp!G04ps04q1O04qz04r1G04r2!I04r404rdO04rk04u0K04u804ucK04ud04ueG04uf04vcK04vd!G04ve!K04vk04xhK04xs04ymK04yo04yzG04z404zfG04zq04zzO053k053tO054w055iK055j055nG0579057iG057k058cG058f!G058g058pO058w0595O059s05a8G05c005c4G05c505dfK05dg05dwG05dx05e3K05e805ehO05ez05f7G05fk05fmG05fn05ggK05gh05gtG05gu05gvK05gw05h5O05h605idK05ie05irG05j405k3K05k405knG05kw05l5O05l905lbK05lc05llO05lm05mlK05mo05mwK05n405oaK05od05ofK05ow05oyG05p005pkG05pl05poK05pp!G05pq05pvK05pw!G05px05pyK05pz05q1G05q2!K05q805vjK05vk05x5G05x705xbG05xc0651K06540659K065c066dK066g066lK066o066vK066x!K066z!K0671!K0673067xK0680069gK069i069oK069q!K069u069wK069y06a4K06a806abK06ae06ajK06ao06b0K06b606b8K06ba06bgK06bk06bqR06bs06buR06bw!G06bx!Q06by06bzI06c806c9N06ck!N06cn!L06co06cpF06cq06cuI06cv!P06db06dcP06dg!M06dw!P06e7!R06e806ecI06ee06enI06ep!K06f3!K06fk06fwK06hc06i8G06iq!K06iv!K06iy06j7K06j9!K06jd06jhK06jo!K06jq!K06js!K06ju06jxK06jz06k9K06kc06kfK06kl06kpK06ku!K06lc06mgK079207ahK08ow08q6K08q808riK08rk08v8K08vf08viK08vj08vlG08vm08vnK08w008x1K08x3!K08x9!K08xc08yvK08z3!K08zj!G08zk0906K090g090mK090o090uK090w0912K0914091aK091c091iK091k091qK091s091yK09200926K09280933G094f!K09hc!R09hh!K09ii09inG09ip09itJ09iz09j0K09ll09lmG09ln09loJ09ls09oaJ09oc09ofJ09ol09prK09pt09seK09sw09trK09v409vjJ0a1c0a2mJ0a2o0a53J0vls0wi4K0wk00wl9K0wlc0wssK0wsw0wtbK0wtc0wtlO0wtm0wtnK0wu80wviK0wvj0wvmG0wvo0wvxG0wvz0wwtK0wwu0wwvG0www0wz3K0wz40wz5G0wzs0x4vK0x4y0x56K0x6d0x6pK0x6q!G0x6r0x6tK0x6u!G0x6v0x6yK0x6z!G0x700x7mK0x7n0x7rG0x7w!G0x8g0x9vK0xa80xa9G0xaa0xbnK0xbo0xc5G0xcg0xcpO0xcw0xddG0xde0xdjK0xdn!K0xdp0xdqK0xdr!G0xds0xe1O0xe20xetK0xeu0xf1G0xf40xfqK0xfr0xg3G0xgg0xh8K0xhc0xhfG0xhg0xiqK0xir0xj4G0xjj!K0xjk0xjtO0xk5!G0xkg0xkpO0xkw0xm0K0xm10xmeG0xmo0xmqK0xmr!G0xms0xmzK0xn00xn1G0xn40xndO0xob0xodG0xps!G0xpu0xpwG0xpz0xq0G0xq60xq7G0xq9!G0xr40xreK0xrf0xrjG0xrm0xroK0xrp0xrqG0xs10xs6K0xs90xseK0xsh0xsmK0xsw0xt2K0xt40xtaK0xtc0xuxK0xv40xyaK0xyb0xyiG0xyk0xylG0xyo0xyxO0xz416lfK16ls16meK16mj16nvK1dkw1dl2K1dlf1dljK1dlp!C1dlq!G1dlr1dm0C1dm21dmeC1dmg1dmkC1dmm!C1dmo1dmpC1dmr1dmsC1dmu1dn3C1dn41dptK1dqr1e0tK1e1c1e33K1e361e4nK1e5s1e63K1e681e6nG1e6o!M1e6r!L1e6s!M1e741e7jG1e7n1e7oP1e8d1e8fP1e8g!M1e8i!N1e8k!M1e8l!L1e9c1e9gK1e9i1ed8K1edb!I1edj!N1edo!M1edq!N1eds1ee1O1ee2!L1ee3!M1ee91eeyK1ef3!P1ef51efuK1eg61ehpJ1ehq1ehrG1ehs1eimK1eiq1eivK1eiy1ej3K1ej61ejbK1eje1ejgK1ek91ekbI1ekg1ekrK1ekt1eliK1elk1em2K1em41em5K1em71emlK1emo1en1K1eo01ereK1etc1eusK1eyl!G1f281f30K1f341f4gK1f4w!G1f5s1f6nK1f711f7uK1f801f91K1f921f96G1f9c1fa5K1fa81fb7K1fbc1fbjK1fbl1fbpK1fcw1fh9K1fhc1fhlO1fhs1firK1fiw1fjvK1fk01fl3K1flc1fmrK1fr41fzqK1g001g0lK1g0w1g13K1g5c1g5hK1g5k!K1g5m1g6tK1g6v1g6wK1g70!K1g731g7pK1g801g8mK1g8w1g9qK1gbk1gc2K1gc41gc5K1gcg1gd1K1gdc1ge1K1gg01ghjK1ghq1ghrK1gjk!K1gjl1gjnG1gjp1gjqG1gjw1gjzG1gk01gk3K1gk51gk7K1gk91gl1K1gl41gl6G1glb!G1gm81gn0K1gn41gnwK1gow1gp3K1gp51gpwK1gpx1gpyG1gqo1gs5K1gsg1gt1K1gtc1gtuK1gu81gupK1gxs1gzsK1h1c1h2qK1h341h4iK1h4w1h5vK1h5w1h5zG1h681h6hO1hfk1hgpK1hgr1hgsG1hgw1hgxK1hj41hjwK1hk7!K1hkg1hl1K1hl21hlcG1ho01hokK1hpc1hpyK1hq81hqaG1hqb1hrrK1hrs1hs6G1ht21htbO1htr1htuG1htv1hv3K1hv41hveG1hvh!I1hvx!I1hw01hwoK1hww1hx5O1hxc1hxeG1hxf1hyeK1hyf1hysG1hyu1hz3O1hz8!K1hz91hzaG1hzb!K1hzk1i0iK1i0j!G1i0m!K1i0w1i0yG1i0z1i2aK1i2b1i2oG1i2p1i2sK1i2x1i30G1i321i33G1i341i3dO1i3e!K1i3g!K1i4g1i4xK1i4z1i5nK1i5o1i5zG1i66!G1i801i86K1i88!K1i8a1i8dK1i8f1i8tK1i8v1i94K1i9c1iamK1ian1iayG1ib41ibdO1ibk1ibnG1ibp1ibwK1ibz1ic0K1ic31icoK1icq1icwK1icy1iczK1id11id5K1id71id8G1id9!K1ida1idgG1idj1idkG1idn1idpG1ids!K1idz!G1ie51ie9K1iea1iebG1iee1iekG1ieo1iesG1iio1ik4K1ik51ikmG1ikn1ikqK1ikw1il5O1ila!G1ilb1ildK1im81injK1ink1io3G1io41io5K1io7!K1iog1iopO1itc1iumK1iun1iutG1iuw1iv4G1ivs1ivvK1ivw1ivxG1iww1iy7K1iy81iyoG1iys!K1iz41izdO1j0g1j1mK1j1n1j1zG1j20!K1j281j2hO1j4t1j57G1j5c1j5lO1jb41jcbK1jcc1jcqG1jfk1jhbK1jhc1jhlO1ji71jieK1jih!K1jik1jirK1jit1jiuK1jiw1jjjK1jjk1jjpG1jjr1jjsG1jjv1jjyG1jjz!K1jk0!G1jk1!K1jk21jk3G1jkg1jkpO1jmo1jmvK1jmy1jo0K1jo11jo7G1joa1jogG1joh!K1joj!K1jok!G1jpc!K1jpd1jpmG1jpn1jqqK1jqr1jqxG1jqy!K1jqz1jr2G1jrb!G1jrk!K1jrl1jrvG1jrw1jt5K1jt61jtlG1jtp!K1juo1jw8K1k3k1k3sK1k3u1k4uK1k4v1k52G1k541k5bG1k5c!K1k5s1k61O1k6q1k7jK1k7m1k87G1k891k8mG1kao1kauK1kaw1kaxK1kaz1kc0K1kc11kc6G1kca!G1kcc1kcdG1kcf1kclG1kcm!K1kcn!G1kcw1kd5O1kdc1kdhK1kdj1kdkK1kdm1kehK1kei1kemG1keo1kepG1ker1kevG1kew!K1kf41kfdO1ko01koiK1koj1komG1kts!K1kw01lllK1log1lriK1ls01lxfK1o1s1oviK1ovk1ovsI1s001sg6K1z401zjsK1zk01zkuK1zkw1zl5O1zo01zotK1zow1zp0G1zpc1zqnK1zqo1zquG1zr41zr7K1zrk1zrtO1zs31zsnK1zst1ztbK20cg20e7K20hs20juK20jz!G20k0!K20k120ljG20lr20luG20lv20m7K20o020o1K20o3!K20o4!G20og20ohG2dc0!J2dlw2dlzJ2fpc2fsaK2fsg2fssK2fsw2ft4K2ftc2ftlK2ftp2ftqG2fts2ftvI2jxh2jxlG2jxp2jxuG2jxv2jy2I2jy32jyaG2jyd2jyjG2jze2jzhG2k3m2k3oG2kg02kicK2kie2kkcK2kke2kkfK2kki!K2kkl2kkmK2kkp2kksK2kku2kl5K2kl7!K2kl92klfK2klh2kn9K2knb2kneK2knh2knoK2knq2knwK2kny2kopK2kor2kouK2kow2kp0K2kp2!K2kp62kpcK2kpe2kytK2kyw2kzkK2kzm2l0aK2l0c2l16K2l182l1wK2l1y2l2sK2l2u2l3iK2l3k2l4eK2l4g2l54K2l562l60K2l622l6qK2l6s2l6zK2l722l8fO2lmo2lo6G2lob2lpoG2lpx!G2lqc!G2lqz2lr3G2lr52lrjG2mtc2mtiG2mtk2mu0G2mu32mu9G2mub2mucG2mue2muiG2n0g2n1oK2n1s2n1yG2n1z2n25K2n282n2hO2n2m!K2ncw2ne3K2ne42ne7G2ne82nehO2oe82ojoK2ok02ok6G2olc2on7K2on82oneG2onf!K2onk2ontO2pkw2pkzK2pl12plrK2plt2pluK2plw!K2plz!K2pm12pmaK2pmc2pmfK2pmh!K2pmj!K2pmq!K2pmv!K2pmx!K2pmz!K2pn12pn3K2pn52pn6K2pn8!K2pnb!K2pnd!K2pnf!K2pnh!K2pnj!K2pnl2pnmK2pno!K2pnr2pnuK2pnw2po2K2po42po7K2po92pocK2poe!K2pog2popK2por2pp7K2ppd2ppfK2pph2pplK2ppn2pq3K2q7k2q89K2q8g2q95K2q9c2qa1K2qcm2qdbH2qrf2qrjG2sc02sc9Ojny9!Ijnz4jo1rGjo5cjobzG'; +export 'package:web_unicode/web_unicode.dart' show WordCharProperty; UnicodePropertyLookup wordLookup = UnicodePropertyLookup.fromPackedData( - _packedWordBreakProperties, - 231, + packedWordBreakProperties, + singleWordBreakRangesCount, WordCharProperty.values, - WordCharProperty.Unknown, + defaultWordCharProperty, ); diff --git a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index fda0324a3f506..76b5b4543ca2a 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -724,15 +724,15 @@ class EditingState { final DomHTMLInputElement element = domElement! as DomHTMLInputElement; return EditingState( text: element.value, - baseOffset: element.selectionStart, - extentOffset: element.selectionEnd); + baseOffset: element.selectionStart?.toInt(), + extentOffset: element.selectionEnd?.toInt()); } else if (domInstanceOfString(domElement, 'HTMLTextAreaElement')) { final DomHTMLTextAreaElement element = domElement! as DomHTMLTextAreaElement; return EditingState( text: element.value, - baseOffset: element.selectionStart, - extentOffset: element.selectionEnd); + baseOffset: element.selectionStart?.toInt(), + extentOffset: element.selectionEnd?.toInt()); } else { throw UnsupportedError('Initialized with unsupported input type'); } diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart index 953235213008e..7010ece2079c6 100644 --- a/lib/web_ui/lib/src/engine/window.dart +++ b/lib/web_ui/lib/src/engine/window.dart @@ -247,14 +247,14 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow { /// text editing to make sure inset is correctly reported to /// framework. final double docWidth = - domDocument.documentElement!.clientWidth.toDouble(); + domDocument.documentElement!.clientWidth; final double docHeight = - domDocument.documentElement!.clientHeight.toDouble(); + domDocument.documentElement!.clientHeight; windowInnerWidth = docWidth * devicePixelRatio; windowInnerHeight = docHeight * devicePixelRatio; } else { - windowInnerWidth = viewport.width!.toDouble() * devicePixelRatio; - windowInnerHeight = viewport.height!.toDouble() * devicePixelRatio; + windowInnerWidth = viewport.width! * devicePixelRatio; + windowInnerHeight = viewport.height! * devicePixelRatio; } } else { windowInnerWidth = domWindow.innerWidth! * devicePixelRatio; @@ -280,7 +280,7 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow { windowInnerHeight = domDocument.documentElement!.clientHeight * devicePixelRatio; } else { - windowInnerHeight = viewport.height!.toDouble() * devicePixelRatio; + windowInnerHeight = viewport.height! * devicePixelRatio; } } else { windowInnerHeight = domWindow.innerHeight! * devicePixelRatio; @@ -309,8 +309,8 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow { double width = 0; if (domWindow.visualViewport != null) { height = - domWindow.visualViewport!.height!.toDouble() * devicePixelRatio; - width = domWindow.visualViewport!.width!.toDouble() * devicePixelRatio; + domWindow.visualViewport!.height! * devicePixelRatio; + width = domWindow.visualViewport!.width! * devicePixelRatio; } else { height = domWindow.innerHeight! * devicePixelRatio; width = domWindow.innerWidth! * devicePixelRatio; diff --git a/lib/web_ui/pubspec.yaml b/lib/web_ui/pubspec.yaml index 96520004a6d72..7d280a9a7c239 100644 --- a/lib/web_ui/pubspec.yaml +++ b/lib/web_ui/pubspec.yaml @@ -9,6 +9,9 @@ dependencies: js: 0.6.4 meta: ^1.7.0 + web_unicode: + path: ../../third_party/web_unicode + dev_dependencies: archive: 3.1.2 args: any diff --git a/lib/web_ui/test/canvaskit/image_golden_test.dart b/lib/web_ui/test/canvaskit/image_golden_test.dart index fd32c13be19e6..2353280641064 100644 --- a/lib/web_ui/test/canvaskit/image_golden_test.dart +++ b/lib/web_ui/test/canvaskit/image_golden_test.dart @@ -772,7 +772,7 @@ void _testCkBrowserImageDecoder() { final ImageDecoder? decoder1 = image.debugCachedWebDecoder; expect(decoder1, isNotNull); expect(image.frameCount, 3); - expect(image.repetitionCount, double.infinity); + expect(image.repetitionCount, -1); // A frame can be decoded right away. final ui.FrameInfo frame1 = await image.getNextFrame(); diff --git a/lib/web_ui/test/canvaskit/path_test.dart b/lib/web_ui/test/canvaskit/path_test.dart index 4aec08ebae67b..bad26e4a9e2d8 100644 --- a/lib/web_ui/test/canvaskit/path_test.dart +++ b/lib/web_ui/test/canvaskit/path_test.dart @@ -45,12 +45,6 @@ void testMain() { path.addOval(const ui.Rect.fromLTRB(10, 10, 100, 100)); expect(path.computeMetrics().length, 2); - // Path metrics can be iterated over multiple times. - final ui.PathMetrics metrics = path.computeMetrics(); - expect(metrics.toList().length, 2); - expect(metrics.toList().length, 2); - expect(metrics.toList().length, 2); - // Can simultaneously iterate over multiple metrics from the same path. final ui.PathMetrics metrics1 = path.computeMetrics(); final ui.PathMetrics metrics2 = path.computeMetrics(); @@ -68,8 +62,7 @@ void testMain() { expect(iter2.moveNext(), isFalse); expect(() => iter1.current, throwsRangeError); expect(() => iter2.current, throwsRangeError); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/115327 - }, skip: true); + }); test('CkPath.reset', () { final ui.Path path = ui.Path(); @@ -171,8 +164,7 @@ void testMain() { expect(measure0.extractPath(0, 15).getBounds(), const ui.Rect.fromLTRB(0, 0, 10, 5)); expect(measure1.contourIndex, 1); expect(measure1.extractPath(0, 15).getBounds(), const ui.Rect.fromLTRB(20, 20, 30, 25)); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/115327 - }, skip: true); + }); test('Path.from', () { const ui.Rect rect1 = ui.Rect.fromLTRB(0, 0, 10, 10); diff --git a/lib/web_ui/test/engine/semantics/text_field_test.dart b/lib/web_ui/test/engine/semantics/text_field_test.dart index 879a3e2f97405..4e1320dd3d85b 100644 --- a/lib/web_ui/test/engine/semantics/text_field_test.dart +++ b/lib/web_ui/test/engine/semantics/text_field_test.dart @@ -63,6 +63,29 @@ void testMain() { semantics().semanticsEnabled = false; }); + test('tap detection works', () async { + debugBrowserEngineOverride = BrowserEngine.webkit; + debugOperatingSystemOverride = OperatingSystem.iOs; + + final SemanticsActionLogger logger = SemanticsActionLogger(); + semantics() + ..debugOverrideTimestampFunction(() => _testTime) + ..semanticsEnabled = true; + + createTextFieldSemantics(value: 'hello'); + + final DomElement textField = appHostNode + .querySelector('input[data-semantics-role="text-field"]')!; + + textField.dispatchEvent(createDomPointerEvent('pointerdown')); + textField.dispatchEvent(createDomPointerEvent('pointerup')); + + expect(await logger.idLog.first, 0); + expect(await logger.actionLog.first, ui.SemanticsAction.tap); + + semantics().semanticsEnabled = false; + }); + // TODO(yjbanov): this test will need to be adjusted for Safari when we add // Safari testing. test('sends a tap action when browser requests focus', () async { diff --git a/lib/web_ui/test/engine/surface/scene_builder_test.dart b/lib/web_ui/test/engine/surface/scene_builder_test.dart index 05dd5b7d1c38c..e0535d7351847 100644 --- a/lib/web_ui/test/engine/surface/scene_builder_test.dart +++ b/lib/web_ui/test/engine/surface/scene_builder_test.dart @@ -35,7 +35,7 @@ void testMain() { test('pushTransform implements surface lifecycle', () { testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) { return sceneBuilder.pushTransform( - (Matrix4.identity()..scale(domWindow.devicePixelRatio as double)).toFloat64()); + (Matrix4.identity()..scale(domWindow.devicePixelRatio)).toFloat64()); }, () { return ''''''; }); @@ -595,8 +595,8 @@ void testMain() { final DomElement content = builder.build().webOnlyRootElement!; final DomCanvasElement canvas = content.querySelector('canvas')! as DomCanvasElement; - final int unscaledWidth = canvas.width!; - final int unscaledHeight = canvas.height!; + final int unscaledWidth = canvas.width!.toInt(); + final int unscaledHeight = canvas.height!.toInt(); // Force update to scene which will utilize reuse code path. final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder(); @@ -627,8 +627,8 @@ void testMain() { final DomElement content = builder.build().webOnlyRootElement!; final DomCanvasElement canvas = content.querySelector('canvas')! as DomCanvasElement; - final int unscaledWidth = canvas.width!; - final int unscaledHeight = canvas.height!; + final int unscaledWidth = canvas.width!.toInt(); + final int unscaledHeight = canvas.height!.toInt(); // Force update to scene which will utilize reuse code path. final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder(); diff --git a/lib/web_ui/test/engine/surface/surface_test.dart b/lib/web_ui/test/engine/surface/surface_test.dart index 5a57d85ed6c59..4b78dec4f7238 100644 --- a/lib/web_ui/test/engine/surface/surface_test.dart +++ b/lib/web_ui/test/engine/surface/surface_test.dart @@ -160,7 +160,7 @@ void testMain() { final SurfaceSceneBuilder builder1 = SurfaceSceneBuilder(); final PersistedTransform a1 = builder1.pushTransform( - (Matrix4.identity()..scale(domWindow.devicePixelRatio as double)).toFloat64()) as PersistedTransform; + (Matrix4.identity()..scale(domWindow.devicePixelRatio)).toFloat64()) as PersistedTransform; final PersistedOpacity b1 = builder1.pushOpacity(100) as PersistedOpacity; final PersistedTransform c1 = builder1.pushTransform(Matrix4.identity().toFloat64()) as PersistedTransform; @@ -181,7 +181,7 @@ void testMain() { final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder(); final PersistedTransform a2 = builder2.pushTransform( - (Matrix4.identity()..scale(domWindow.devicePixelRatio as double)).toFloat64(), + (Matrix4.identity()..scale(domWindow.devicePixelRatio)).toFloat64(), oldLayer: a1) as PersistedTransform; final PersistedTransform c2 = builder2.pushTransform(Matrix4.identity().toFloat64(), oldLayer: c1) as PersistedTransform; diff --git a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart index a4ad2e240ecb3..3b985102d4f4c 100644 --- a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart @@ -111,6 +111,25 @@ Future testMain() async { rc.restore(); await canvasScreenshot(rc, 'canvas_image_blend_and_text'); }); + + test('Does not re-use styles with same image src', () async { + final RecordingCanvas rc = RecordingCanvas( + const Rect.fromLTRB(0, 0, 400, 400)); + final HtmlImage flutterImage = createFlutterLogoTestImage(); + rc.save(); + rc.drawRect(const Rect.fromLTWH(0, 50, 200, 50), makePaint() + ..color = white); + rc.drawImage(flutterImage, const Offset(0, 50), + makePaint() + ..colorFilter = const EngineColorFilter.mode(red, BlendMode.modulate)); + + // Expect that the colorFilter is only applied to the first image, since the + // colorFilter is applied to a clone of the flutterImage and not the original + rc.drawImage(flutterImage, const Offset(0, 100), makePaint()); + + rc.restore(); + await canvasScreenshot(rc, 'canvas_image_same_src'); + }); } Paragraph createTestParagraph() { diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index aaf279610562c..9870d5e7804ca 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -211,7 +211,15 @@ bool RuntimeController::ReportTimings(std::vector timings) { return false; } -bool RuntimeController::NotifyIdle(fml::TimePoint deadline) { +bool RuntimeController::NotifyIdle(fml::TimeDelta deadline) { + if (deadline - fml::TimeDelta::FromMicroseconds(Dart_TimelineGetMicros()) < + fml::TimeDelta::FromMilliseconds(1)) { + // There's less than 1ms left before the deadline. Upstream callers do not + // check to see if the deadline is in the past, and work after this point + // will be in vain. + return false; + } + std::shared_ptr root_isolate = root_isolate_.lock(); if (!root_isolate) { return false; @@ -225,12 +233,12 @@ bool RuntimeController::NotifyIdle(fml::TimePoint deadline) { return false; } - Dart_NotifyIdle(deadline.ToEpochDelta().ToMicroseconds()); + Dart_NotifyIdle(deadline.ToMicroseconds()); // Idle notifications being in isolate scope are part of the contract. if (idle_notification_callback_) { TRACE_EVENT0("flutter", "EmbedderIdleNotification"); - idle_notification_callback_(deadline.ToEpochDelta().ToMicroseconds()); + idle_notification_callback_(deadline.ToMicroseconds()); } return true; } diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index f6c50fbdd8c80..3f8fa2dcb3ab4 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -358,7 +358,7 @@ class RuntimeController : public PlatformConfigurationClient { /// /// @return If the idle notification was forwarded to the running isolate. /// - virtual bool NotifyIdle(fml::TimePoint deadline); + virtual bool NotifyIdle(fml::TimeDelta deadline); //---------------------------------------------------------------------------- /// @brief Notify the Dart VM that the attached flutter view has been diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 6468f0f45f627..b396b0a4e2da0 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -57,12 +57,6 @@ void Animator::EnqueueTraceFlowId(uint64_t trace_flow_id) { }); } -static fml::TimePoint FxlToDartOrEarlier(fml::TimePoint time) { - auto dart_now = fml::TimeDelta::FromMicroseconds(Dart_TimelineGetMicros()); - fml::TimePoint fxl_now = fml::TimePoint::Now(); - return fml::TimePoint::FromEpochDelta(time - fxl_now + dart_now); -} - void Animator::BeginFrame( std::unique_ptr frame_timings_recorder) { TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", @@ -81,7 +75,6 @@ void Animator::BeginFrame( } frame_scheduled_ = false; - notify_idle_task_id_++; regenerate_layer_tree_ = false; pending_frame_semaphore_.Signal(); @@ -106,34 +99,29 @@ void Animator::BeginFrame( FML_DCHECK(producer_continuation_); const fml::TimePoint frame_target_time = frame_timings_recorder_->GetVsyncTargetTime(); - dart_frame_deadline_ = FxlToDartOrEarlier(frame_target_time); + dart_frame_deadline_ = frame_target_time.ToEpochDelta(); uint64_t frame_number = frame_timings_recorder_->GetFrameNumber(); delegate_.OnAnimatorBeginFrame(frame_target_time, frame_number); if (!frame_scheduled_ && has_rendered_) { - // Under certain workloads (such as our parent view resizing us, which is - // communicated to us by repeat viewport metrics events), we won't - // actually have a frame scheduled yet, despite the fact that we *will* be - // producing a frame next vsync (it will be scheduled once we receive the - // viewport event). Because of this, we hold off on calling - // |OnAnimatorNotifyIdle| for a little bit, as that could cause garbage - // collection to trigger at a highly undesirable time. + // Wait a tad more than 3 60hz frames before reporting a big idle period. + // This is a heuristic that is meant to avoid giving false positives to the + // VM when we are about to schedule a frame in the next vsync, the idea + // being that if there have been three vsyncs with no frames it's a good + // time to start doing GC work. task_runners_.GetUITaskRunner()->PostDelayedTask( - [self = weak_factory_.GetWeakPtr(), - notify_idle_task_id = notify_idle_task_id_]() { + [self = weak_factory_.GetWeakPtr()]() { if (!self) { return; } - // If our (this task's) task id is the same as the current one - // (meaning there were no follow up frames to the |BeginFrame| call - // that posted this task) and no frame is currently scheduled, then - // assume that we are idle, and notify the engine of this. - if (notify_idle_task_id == self->notify_idle_task_id_ && - !self->frame_scheduled_) { + auto now = fml::TimeDelta::FromMicroseconds(Dart_TimelineGetMicros()); + // If there's a frame scheduled, bail. + // If there's no frame scheduled, but we're not yet past the last + // vsync deadline, bail. + if (!self->frame_scheduled_ && now > self->dart_frame_deadline_) { TRACE_EVENT0("flutter", "BeginFrame idle callback"); self->delegate_.OnAnimatorNotifyIdle( - FxlToDartOrEarlier(fml::TimePoint::Now() + - fml::TimeDelta::FromMicroseconds(100000))); + now + fml::TimeDelta::FromMilliseconds(100)); } }, kNotifyIdleTaskWaitTime); diff --git a/shell/common/animator.h b/shell/common/animator.h index 116682d2d76ee..79373b5f0f246 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -34,7 +34,7 @@ class Animator final { virtual void OnAnimatorBeginFrame(fml::TimePoint frame_target_time, uint64_t frame_number) = 0; - virtual void OnAnimatorNotifyIdle(fml::TimePoint deadline) = 0; + virtual void OnAnimatorNotifyIdle(fml::TimeDelta deadline) = 0; virtual void OnAnimatorUpdateLatestFrameTargetTime( fml::TimePoint frame_target_time) = 0; @@ -100,13 +100,12 @@ class Animator final { std::unique_ptr frame_timings_recorder_; uint64_t frame_request_number_ = 1; - fml::TimePoint dart_frame_deadline_; + fml::TimeDelta dart_frame_deadline_; std::shared_ptr layer_tree_pipeline_; fml::Semaphore pending_frame_semaphore_; LayerTreePipeline::ProducerContinuation producer_continuation_; bool regenerate_layer_tree_ = false; bool frame_scheduled_ = false; - int notify_idle_task_id_ = 0; SkISize last_layer_tree_size_ = {0, 0}; std::deque trace_flow_ids_; bool has_rendered_ = false; diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc index 0a68325e89f1b..05c728c57ae16 100644 --- a/shell/common/animator_unittests.cc +++ b/shell/common/animator_unittests.cc @@ -28,7 +28,7 @@ class FakeAnimatorDelegate : public Animator::Delegate { MOCK_METHOD2(OnAnimatorBeginFrame, void(fml::TimePoint frame_target_time, uint64_t frame_number)); - void OnAnimatorNotifyIdle(fml::TimePoint deadline) override { + void OnAnimatorNotifyIdle(fml::TimeDelta deadline) override { notify_idle_called_ = true; } diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 85db9043eeff7..7d2a63d57cad2 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -254,15 +254,10 @@ void Engine::BeginFrame(fml::TimePoint frame_time, uint64_t frame_number) { } void Engine::ReportTimings(std::vector timings) { - TRACE_EVENT0("flutter", "Engine::ReportTimings"); runtime_controller_->ReportTimings(std::move(timings)); } -void Engine::NotifyIdle(fml::TimePoint deadline) { - auto trace_event = std::to_string(deadline.ToEpochDelta().ToMicroseconds() - - Dart_TimelineGetMicros()); - TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta", - trace_event.c_str()); +void Engine::NotifyIdle(fml::TimeDelta deadline) { runtime_controller_->NotifyIdle(deadline); } diff --git a/shell/common/engine.h b/shell/common/engine.h index 82e041e6ff2d1..70402c24a7876 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -552,7 +552,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// corresponding sweep can be performed within the /// deadline. /// - void NotifyIdle(fml::TimePoint deadline); + void NotifyIdle(fml::TimeDelta deadline); //---------------------------------------------------------------------------- /// @brief Notifies the engine that the attached flutter view has been diff --git a/shell/common/engine_unittests.cc b/shell/common/engine_unittests.cc index a5f8e4f4c6353..c2c9a84f634da 100644 --- a/shell/common/engine_unittests.cc +++ b/shell/common/engine_unittests.cc @@ -77,7 +77,7 @@ class MockRuntimeController : public RuntimeController { MOCK_METHOD3(LoadDartDeferredLibraryError, void(intptr_t, const std::string, bool)); MOCK_CONST_METHOD0(GetDartVM, DartVM*()); - MOCK_METHOD1(NotifyIdle, bool(fml::TimePoint)); + MOCK_METHOD1(NotifyIdle, bool(fml::TimeDelta)); }; std::unique_ptr MakePlatformMessage( diff --git a/shell/common/shell.cc b/shell/common/shell.cc index a8bad9ea960b4..693d36a143366 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1133,7 +1133,7 @@ void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time, } // |Animator::Delegate| -void Shell::OnAnimatorNotifyIdle(fml::TimePoint deadline) { +void Shell::OnAnimatorNotifyIdle(fml::TimeDelta deadline) { FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); diff --git a/shell/common/shell.h b/shell/common/shell.h index 79581ce480762..71ee082c0a4ac 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -591,7 +591,7 @@ class Shell final : public PlatformView::Delegate, uint64_t frame_number) override; // |Animator::Delegate| - void OnAnimatorNotifyIdle(fml::TimePoint deadline) override; + void OnAnimatorNotifyIdle(fml::TimeDelta deadline) override; // |Animator::Delegate| void OnAnimatorUpdateLatestFrameTargetTime( diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index 078455d3f8e5b..a799e6bcb4811 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -152,7 +152,7 @@ void ShellTest::SetViewportMetrics(Shell* shell, double width, double height) { latch.Wait(); } -void ShellTest::NotifyIdle(Shell* shell, fml::TimePoint deadline) { +void ShellTest::NotifyIdle(Shell* shell, fml::TimeDelta deadline) { fml::AutoResetWaitableEvent latch; shell->GetTaskRunners().GetUITaskRunner()->PostTask( [&latch, engine = shell->weak_engine_, deadline]() { diff --git a/shell/common/shell_test.h b/shell/common/shell_test.h index 5dad608088c2c..b9e95cc590e8b 100644 --- a/shell/common/shell_test.h +++ b/shell/common/shell_test.h @@ -74,7 +74,7 @@ class ShellTest : public FixtureTest { std::function root)>; static void SetViewportMetrics(Shell* shell, double width, double height); - static void NotifyIdle(Shell* shell, fml::TimePoint deadline); + static void NotifyIdle(Shell* shell, fml::TimeDelta deadline); static void PumpOneFrame(Shell* shell, double width = 1, diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index d5a0158c7ef25..d850eab688012 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -3891,6 +3891,51 @@ TEST_F(ShellTest, PluginUtilitiesCallbackHandleErrorHandling) { DestroyShell(std::move(shell)); } +TEST_F(ShellTest, NotifyIdleRejectsPastAndNearFuture) { + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); + Settings settings = CreateSettingsForFixture(); + ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::Platform | ThreadHost::UI | + ThreadHost::IO | ThreadHost::RASTER); + auto platform_task_runner = thread_host.platform_thread->GetTaskRunner(); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + auto shell = CreateShell(settings, task_runners); + ASSERT_TRUE(DartVMRef::IsInstanceRunning()); + ASSERT_TRUE(ValidateShell(shell.get())); + + fml::AutoResetWaitableEvent latch; + + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("emptyMain"); + RunEngine(shell.get(), std::move(configuration)); + + fml::TaskRunner::RunNowOrPostTask( + task_runners.GetUITaskRunner(), [&latch, &shell]() { + auto runtime_controller = const_cast( + shell->GetEngine()->GetRuntimeController()); + + auto now = fml::TimeDelta::FromMicroseconds(Dart_TimelineGetMicros()); + + EXPECT_FALSE(runtime_controller->NotifyIdle( + now - fml::TimeDelta::FromMilliseconds(10))); + EXPECT_FALSE(runtime_controller->NotifyIdle(now)); + EXPECT_FALSE(runtime_controller->NotifyIdle( + now + fml::TimeDelta::FromNanoseconds(100))); + + EXPECT_TRUE(runtime_controller->NotifyIdle( + now + fml::TimeDelta::FromMilliseconds(100))); + latch.Signal(); + }); + + latch.Wait(); + + DestroyShell(std::move(shell), task_runners); + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); +} + TEST_F(ShellTest, NotifyIdleNotCalledInLatencyMode) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); @@ -3917,7 +3962,9 @@ TEST_F(ShellTest, NotifyIdleNotCalledInLatencyMode) { tonic::DartConverter::FromArguments(args, 0, exception); auto runtime_controller = const_cast( shell->GetEngine()->GetRuntimeController()); - bool success = runtime_controller->NotifyIdle(fml::TimePoint::Now()); + bool success = + runtime_controller->NotifyIdle(fml::TimeDelta::FromMicroseconds( + Dart_TimelineGetMicros() + 100000)); EXPECT_EQ(success, !is_in_latency_mode); latch.CountDown(); })); diff --git a/shell/platform/android/android_egl_surface.cc b/shell/platform/android/android_egl_surface.cc index fa1573a6e25cc..e610f505febed 100644 --- a/shell/platform/android/android_egl_surface.cc +++ b/shell/platform/android/android_egl_surface.cc @@ -21,9 +21,7 @@ void LogLastEGLError() { }; #define _EGL_ERROR_DESC(a) \ - { \ -#a, a \ - } + { #a, a } const EGLNameErrorPair pairs[] = { _EGL_ERROR_DESC(EGL_SUCCESS), diff --git a/shell/platform/android/android_surface_vulkan_impeller.cc b/shell/platform/android/android_surface_vulkan_impeller.cc index f5bf383ab19da..b9588df3ac500 100644 --- a/shell/platform/android/android_surface_vulkan_impeller.cc +++ b/shell/platform/android/android_surface_vulkan_impeller.cc @@ -14,6 +14,7 @@ #include "flutter/shell/gpu/gpu_surface_vulkan_impeller.h" #include "flutter/vulkan/vulkan_native_surface_android.h" #include "impeller/entity/vk/entity_shaders_vk.h" +#include "impeller/entity/vk/modern_shaders_vk.h" namespace flutter { @@ -23,6 +24,8 @@ std::shared_ptr CreateImpellerContext( std::vector> shader_mappings = { std::make_shared(impeller_entity_shaders_vk_data, impeller_entity_shaders_vk_length), + std::make_shared(impeller_modern_shaders_vk_data, + impeller_modern_shaders_vk_length), }; PFN_vkGetInstanceProcAddr instance_proc_addr = diff --git a/shell/platform/darwin/common/framework/Headers/FlutterMacros.h b/shell/platform/darwin/common/framework/Headers/FlutterMacros.h index 1b9c821ede3dd..da99e10219b76 100644 --- a/shell/platform/darwin/common/framework/Headers/FlutterMacros.h +++ b/shell/platform/darwin/common/framework/Headers/FlutterMacros.h @@ -39,9 +39,9 @@ #if __has_feature(objc_arc) #define FLUTTER_ASSERT_ARC -#define FLUTTER_ASSERT_NOT_ARC #error ARC must be disabled! +#define FLUTTER_ASSERT_NOT_ARC #error ARC must be disabled ! #else -#define FLUTTER_ASSERT_ARC #error ARC must be enabled! +#define FLUTTER_ASSERT_ARC #error ARC must be enabled ! #define FLUTTER_ASSERT_NOT_ARC #endif diff --git a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm index a75711c2b4441..1ab7dcd51d3c4 100644 --- a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm +++ b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm @@ -10,6 +10,7 @@ #include "flutter/impeller/renderer/backend/metal/context_mtl.h" #include "flutter/shell/common/context_options.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#include "impeller/entity/mtl/modern_shaders.h" FLUTTER_ASSERT_ARC @@ -17,6 +18,8 @@ std::vector> shader_mappings = { std::make_shared(impeller_entity_shaders_data, impeller_entity_shaders_length), + std::make_shared(impeller_modern_shaders_data, + impeller_modern_shaders_length), }; auto context = impeller::ContextMTL::Create(shader_mappings, "Impeller Library"); if (!context) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManagerTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManagerTest.mm index de9fadabc34fb..764a64b242cad 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManagerTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManagerTest.mm @@ -19,7 +19,7 @@ namespace flutter { class PointerDataPacket {}; -} +} // namespace flutter /// Sometimes we have to use a custom mock to avoid retain cycles in ocmock. @interface FlutterEnginePartialMock : FlutterEngine diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 40c7ab8e12edc..9208bbf0f89e1 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -32,6 +32,22 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { } @end +// Determines if the final `clipBounds` from a clipRect/clipRRect/clipPath mutator contains the +// `platformview_boundingrect`. +// +// `clip_bounds` is the bounding rect of the rect/rrect/path in the clipRect/clipRRect/clipPath +// mutator. This 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 ClipBoundsContainsPlatformViewBoundingRect(const SkRect& clip_bounds, + const SkRect& platformview_boundingrect, + const SkMatrix& transform_matrix) { + SkRect transforme_clip_bounds = transform_matrix.mapRect(clip_bounds); + return transforme_clip_bounds.contains(platformview_boundingrect); +} + namespace flutter { // Becomes NO if Apple's API changes and blurred backdrop filters cannot be applied. BOOL canApplyBlurBackdrop = YES; @@ -404,7 +420,8 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { } void FlutterPlatformViewsController::ApplyMutators(const MutatorsStack& mutators_stack, - UIView* embedded_view) { + UIView* embedded_view, + const SkRect& bounding_rect) { if (flutter_view_ == nullptr) { return; } @@ -412,39 +429,53 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { ResetAnchor(embedded_view.layer); ChildClippingView* clipView = (ChildClippingView*)embedded_view.superview; - // The UIKit frame is set based on the logical resolution 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. And until this point, we did all the calculation based on the flow - // resolution. So we need to scale down to match UIKit's logical resolution. CGFloat screenScale = [UIScreen mainScreen].scale; - CATransform3D finalTransform = CATransform3DMakeScale(1 / screenScale, 1 / screenScale, 1); UIView* flutter_view = flutter_view_.get(); FlutterClippingMaskView* maskView = [[[FlutterClippingMaskView alloc] initWithFrame:CGRectMake(-clipView.frame.origin.x, -clipView.frame.origin.y, CGRectGetWidth(flutter_view.bounds), - CGRectGetHeight(flutter_view.bounds))] autorelease]; + CGRectGetHeight(flutter_view.bounds)) + screenScale:screenScale] autorelease]; + SkMatrix transformMatrix; NSMutableArray* blurFilters = [[[NSMutableArray alloc] init] autorelease]; + clipView.maskView = nil; auto iter = mutators_stack.Begin(); while (iter != mutators_stack.End()) { switch ((*iter)->GetType()) { case kTransform: { - CATransform3D transform = GetCATransform3DFromSkMatrix((*iter)->GetMatrix()); - finalTransform = CATransform3DConcat(transform, finalTransform); + transformMatrix.preConcat((*iter)->GetMatrix()); break; } - case kClipRect: - [maskView clipRect:(*iter)->GetRect() matrix:finalTransform]; + case kClipRect: { + if (ClipBoundsContainsPlatformViewBoundingRect((*iter)->GetRect(), bounding_rect, + transformMatrix)) { + break; + } + [maskView clipRect:(*iter)->GetRect() matrix:transformMatrix]; + clipView.maskView = maskView; break; - case kClipRRect: - [maskView clipRRect:(*iter)->GetRRect() matrix:finalTransform]; + } + case kClipRRect: { + if (ClipBoundsContainsPlatformViewBoundingRect((*iter)->GetRRect().getBounds(), + bounding_rect, transformMatrix)) { + break; + } + [maskView clipRRect:(*iter)->GetRRect() matrix:transformMatrix]; + clipView.maskView = maskView; break; - case kClipPath: - [maskView clipPath:(*iter)->GetPath() matrix:finalTransform]; + } + case kClipPath: { + if (ClipBoundsContainsPlatformViewBoundingRect((*iter)->GetPath().getBounds(), + bounding_rect, transformMatrix)) { + break; + } + [maskView clipPath:(*iter)->GetPath() matrix:transformMatrix]; + clipView.maskView = maskView; break; + } case kOpacity: embedded_view.alpha = (*iter)->GetAlphaFloat() * embedded_view.alpha; break; @@ -489,6 +520,13 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { [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 @@ -496,10 +534,9 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { // // 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. - CATransform3D reverseTranslate = - CATransform3DMakeTranslation(-clipView.frame.origin.x, -clipView.frame.origin.y, 0); - embedded_view.layer.transform = CATransform3DConcat(finalTransform, reverseTranslate); - clipView.maskView = maskView; + transformMatrix.postTranslate(-clipView.frame.origin.x, -clipView.frame.origin.y); + + embedded_view.layer.transform = flutter::GetCATransform3DFromSkMatrix(transformMatrix); } void FlutterPlatformViewsController::CompositeWithParams(int view_id, @@ -538,7 +575,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { CGFloat screenScale = [UIScreen mainScreen].scale; clippingView.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale, rect.width() / screenScale, rect.height() / screenScale); - ApplyMutators(mutatorStack, touchInterceptor); + ApplyMutators(mutatorStack, touchInterceptor, rect); } EmbedderPaintContext FlutterPlatformViewsController::CompositeEmbeddedView(int view_id) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 56fbc541d3253..9391a4b23b1da 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -1478,6 +1478,74 @@ - (void)testChildClippingViewShouldBeTheBoundingRectOfPlatformView { kFloatCompareEpsilon); } +- (void)testClipsDoNotInterceptWithPlatformViewShouldNotAddMaskView { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest"); + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/thread_task_runner, + /*raster=*/thread_task_runner, + /*ui=*/thread_task_runner, + /*io=*/thread_task_runner); + auto flutterPlatformViewsController = std::make_shared(); + auto platform_view = std::make_unique( + /*delegate=*/mock_delegate, + /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware, + /*platform_views_controller=*/flutterPlatformViewsController, + /*task_runners=*/runners); + + FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = + [[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease]; + flutterPlatformViewsController->RegisterViewFactory( + factory, @"MockFlutterPlatformView", + FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + FlutterResult result = ^(id result) { + }; + flutterPlatformViewsController->OnMethodCall( + [FlutterMethodCall + methodCallWithMethodName:@"create" + arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], + result); + + XCTAssertNotNil(gMockPlatformView); + + UIView* mockFlutterView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)] autorelease]; + flutterPlatformViewsController->SetFlutterView(mockFlutterView); + // Create embedded view params + flutter::MutatorsStack stack; + // Layer tree always pushes a screen scale factor to the stack + SkMatrix screenScaleMatrix = + SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale); + stack.PushTransform(screenScaleMatrix); + SkMatrix translateMatrix = SkMatrix::Translate(5, 5); + // The platform view's rect for this test will be (5, 5, 10, 10) + stack.PushTransform(translateMatrix); + // Push a clip rect, big enough to contain the entire platform view bound + SkRect rect = SkRect::MakeXYWH(0, 0, 25, 25); + stack.PushClipRect(rect); + // Push a clip rrect, big enough to contain the entire platform view bound + SkRect rect_for_rrect = SkRect::MakeXYWH(0, 0, 24, 24); + SkRRect rrect = SkRRect::MakeRectXY(rect_for_rrect, 1, 1); + stack.PushClipRRect(rrect); + // Push a clip path, big enough to contain the entire platform view bound + SkPath path = SkPath::RRect(SkRect::MakeXYWH(0, 0, 23, 23), 1, 1); + stack.PushClipPath(path); + + auto embeddedViewParams = std::make_unique( + SkMatrix::Concat(screenScaleMatrix, translateMatrix), SkSize::Make(5, 5), stack); + + flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); + flutterPlatformViewsController->CompositeEmbeddedView(2); + gMockPlatformView.backgroundColor = UIColor.redColor; + XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]); + ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; + [mockFlutterView addSubview:childClippingView]; + + [mockFlutterView setNeedsLayout]; + [mockFlutterView layoutIfNeeded]; + + XCTAssertNil(childClippingView.maskView); +} + - (void)testClipRect { flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest"); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 9e8009e6fe077..7ec51e3b8ffcf 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -28,20 +28,22 @@ // is replaced with the alpha channel of the |FlutterClippingMaskView|. @interface FlutterClippingMaskView : UIView +- (instancetype)initWithFrame:(CGRect)frame screenScale:(CGFloat)screenScale; + // Adds a clip rect operation to the queue. // // The `clipSkRect` is transformed with the `matrix` before adding to the queue. -- (void)clipRect:(const SkRect&)clipSkRect matrix:(const CATransform3D&)matrix; +- (void)clipRect:(const SkRect&)clipSkRect matrix:(const SkMatrix&)matrix; // Adds a clip rrect operation to the queue. // // The `clipSkRRect` is transformed with the `matrix` before adding to the queue. -- (void)clipRRect:(const SkRRect&)clipSkRRect matrix:(const CATransform3D&)matrix; +- (void)clipRRect:(const SkRRect&)clipSkRRect matrix:(const SkMatrix&)matrix; // Adds a clip path operation to the queue. // // The `path` is transformed with the `matrix` before adding to the queue. -- (void)clipPath:(const SkPath&)path matrix:(const CATransform3D&)matrix; +- (void)clipPath:(const SkPath&)path matrix:(const SkMatrix&)matrix; @end @@ -280,7 +282,13 @@ class FlutterPlatformViewsController { // T_1 is applied to C_2, T_3 and T_4 are applied to C_5, and T_6 is applied to PLATFORM_VIEW. // // After each clip operation, we update the head to the super view of the current head. - void ApplyMutators(const MutatorsStack& mutators_stack, UIView* 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); void CompositeWithParams(int view_id, const EmbeddedViewParams& params); // Allocates a new FlutterPlatformViewLayer if needed, draws the pixels within the rect from diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm index ff70a4b4d2b27..da7f156bafe95 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm @@ -241,6 +241,16 @@ - (NSMutableArray*)backdropFilterSubviews { @interface FlutterClippingMaskView () +// A `CATransform3D` matrix represnts a scale transform that revese UIScreen.scale. +// +// The transform matrix passed in clipRect/clipRRect/clipPath methods are in device coordinate +// space. The transfrom matrix concats `reverseScreenScale` to create a transform matrix in the iOS +// logical coordinates (points). +// +// See https://developer.apple.com/documentation/uikit/uiscreen/1617836-scale?language=objc for +// information about screen scale. +@property(nonatomic) CATransform3D reverseScreenScale; + - (fml::CFRef)getTransformedPath:(CGPathRef)path matrix:(CATransform3D)matrix; @end @@ -250,8 +260,13 @@ @implementation FlutterClippingMaskView { } - (instancetype)initWithFrame:(CGRect)frame { + return [self initWithFrame:frame screenScale:[UIScreen mainScreen].scale]; +} + +- (instancetype)initWithFrame:(CGRect)frame screenScale:(CGFloat)screenScale { if (self = [super initWithFrame:frame]) { self.backgroundColor = UIColor.clearColor; + _reverseScreenScale = CATransform3DMakeScale(1 / screenScale, 1 / screenScale, 1); } return self; } @@ -280,13 +295,16 @@ - (void)drawRect:(CGRect)rect { CGContextRestoreGState(context); } -- (void)clipRect:(const SkRect&)clipSkRect matrix:(const CATransform3D&)matrix { +- (void)clipRect:(const SkRect&)clipSkRect matrix:(const SkMatrix&)matrix { CGRect clipRect = flutter::GetCGRectFromSkRect(clipSkRect); CGPathRef path = CGPathCreateWithRect(clipRect, nil); - paths_.push_back([self getTransformedPath:path matrix:matrix]); + // The `matrix` is based on the physical pixels, convert it to UIKit points. + CATransform3D matrixInPoints = + CATransform3DConcat(flutter::GetCATransform3DFromSkMatrix(matrix), _reverseScreenScale); + paths_.push_back([self getTransformedPath:path matrix:matrixInPoints]); } -- (void)clipRRect:(const SkRRect&)clipSkRRect matrix:(const CATransform3D&)matrix { +- (void)clipRRect:(const SkRRect&)clipSkRRect matrix:(const SkMatrix&)matrix { CGPathRef pathRef = nullptr; switch (clipSkRRect.getType()) { case SkRRect::kEmpty_Type: { @@ -346,13 +364,16 @@ - (void)clipRRect:(const SkRRect&)clipSkRRect matrix:(const CATransform3D&)matri break; } } + // The `matrix` is based on the physical pixels, convert it to UIKit points. + CATransform3D matrixInPoints = + CATransform3DConcat(flutter::GetCATransform3DFromSkMatrix(matrix), _reverseScreenScale); // TODO(cyanglaz): iOS does not seem to support hard edge on CAShapeLayer. It clearly stated that // the CAShaperLayer will be drawn antialiased. Need to figure out a way to do the hard edge // clipping on iOS. - paths_.push_back([self getTransformedPath:pathRef matrix:matrix]); + paths_.push_back([self getTransformedPath:pathRef matrix:matrixInPoints]); } -- (void)clipPath:(const SkPath&)path matrix:(const CATransform3D&)matrix { +- (void)clipPath:(const SkPath&)path matrix:(const SkMatrix&)matrix { if (!path.isValid()) { return; } @@ -411,7 +432,10 @@ - (void)clipPath:(const SkPath&)path matrix:(const CATransform3D&)matrix { } verb = iter.next(pts); } - paths_.push_back([self getTransformedPath:pathRef matrix:matrix]); + // The `matrix` is based on the physical pixels, convert it to UIKit points. + CATransform3D matrixInPoints = + CATransform3DConcat(flutter::GetCATransform3DFromSkMatrix(matrix), _reverseScreenScale); + paths_.push_back([self getTransformedPath:pathRef matrix:matrixInPoints]); } - (fml::CFRef)getTransformedPath:(CGPathRef)path matrix:(CATransform3D)matrix { diff --git a/shell/platform/darwin/ios/ios_surface_metal_impeller.mm b/shell/platform/darwin/ios/ios_surface_metal_impeller.mm index 1aba7895cb2f3..31dcd7a5e99aa 100644 --- a/shell/platform/darwin/ios/ios_surface_metal_impeller.mm +++ b/shell/platform/darwin/ios/ios_surface_metal_impeller.mm @@ -48,6 +48,12 @@ if (!CGSizeEqualToSize(drawable_size, layer.drawableSize)) { layer.drawableSize = drawable_size; } + + // When there are platform views in the scene, the drawable needs to be presented in the same + // transaction as the one created for platform views. When the drawable are being presented from + // the raster thread, there is no such transaction. + layer.presentsWithTransaction = [[NSThread currentThread] isMainThread]; + return layer; } diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 059b2bc4e57e7..935a3c3591978 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -165,14 +165,14 @@ executable("flutter_desktop_darwin_unittests") { sources = [ "framework/Source/AccessibilityBridgeMacTest.mm", - "framework/Source/FlutterChannelKeyResponderUnittests.mm", - "framework/Source/FlutterCompositorUnittests.mm", - "framework/Source/FlutterEmbedderExternalTextureUnittests.mm", - "framework/Source/FlutterEmbedderKeyResponderUnittests.mm", + "framework/Source/FlutterChannelKeyResponderTest.mm", + "framework/Source/FlutterCompositorTest.mm", + "framework/Source/FlutterEmbedderExternalTextureTest.mm", + "framework/Source/FlutterEmbedderKeyResponderTest.mm", "framework/Source/FlutterEngineTest.mm", "framework/Source/FlutterEngineTestUtils.h", "framework/Source/FlutterEngineTestUtils.mm", - "framework/Source/FlutterKeyboardManagerUnittests.mm", + "framework/Source/FlutterKeyboardManagerTest.mm", "framework/Source/FlutterMenuPluginTest.mm", "framework/Source/FlutterPlatformNodeDelegateMacTest.mm", "framework/Source/FlutterPlatformViewControllerTest.mm", @@ -183,7 +183,7 @@ executable("flutter_desktop_darwin_unittests") { "framework/Source/FlutterViewControllerTest.mm", "framework/Source/FlutterViewControllerTestUtils.h", "framework/Source/FlutterViewControllerTestUtils.mm", - "framework/Source/FlutterViewEngineProviderUnitTests.mm", + "framework/Source/FlutterViewEngineProviderTest.mm", "framework/Source/TestFlutterPlatformView.h", "framework/Source/TestFlutterPlatformView.mm", ] diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterDartProject.h b/shell/platform/darwin/macos/framework/Headers/FlutterDartProject.h index e888273c880ca..4a83e4d3e6062 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterDartProject.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterDartProject.h @@ -44,7 +44,7 @@ FLUTTER_DARWIN_EXPORT * * Set this to nil to pass no arguments to the Dart entrypoint. */ -@property(nonatomic, nullable, strong) NSArray* dartEntrypointArguments; +@property(nonatomic, nullable, copy) NSArray* dartEntrypointArguments; @end diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index 53e26fbad4da6..4dea666e1262c 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -115,6 +115,6 @@ FLUTTER_DARWIN_EXPORT * } * ``` */ -@property(readwrite, nonatomic, nullable) NSColor* backgroundColor; +@property(readwrite, nonatomic, nullable, copy) NSColor* backgroundColor; @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.h b/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.h index 354d21a6fe59f..809c174c37343 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.h @@ -11,13 +11,6 @@ */ @interface FlutterRenderBackingStore : NSObject -@end - -/** - * Wraps a Metal texture. - */ -@interface FlutterMetalRenderBackingStore : FlutterRenderBackingStore - /** * MTLTexture referenced by this backing store instance. */ diff --git a/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.mm b/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.mm index 8a0119203a975..61404932c9c2d 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.mm @@ -5,9 +5,6 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.h" @implementation FlutterRenderBackingStore -@end - -@implementation FlutterMetalRenderBackingStore - (instancetype)initWithTexture:(id)texture { self = [super init]; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderTest.mm similarity index 100% rename from shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm rename to shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderTest.mm diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm index 1cb1a412af769..ccdfaec180c2a 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm @@ -37,8 +37,7 @@ StartFrame(); // If the backing store is for the first layer, return the MTLTexture for the // FlutterView. - FlutterMetalRenderBackingStore* backingStore = - reinterpret_cast([view backingStoreForSize:size]); + FlutterRenderBackingStore* backingStore = [view backingStoreForSize:size]; backing_store_out->metal.texture.texture = (__bridge FlutterMetalTextureHandle)backingStore.texture; } else { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositorUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm similarity index 90% rename from shell/platform/darwin/macos/framework/Source/FlutterCompositorUnittests.mm rename to shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm index b9f9f10b7807c..576af2bbac152 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositorUnittests.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm @@ -10,16 +10,16 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h" #import "flutter/testing/testing.h" -@interface FlutterViewMockProviderMetal : NSObject { +@interface FlutterViewMockProvider : NSObject { FlutterView* _defaultView; } /** - * Create a FlutterViewMockProviderMetal with the provided view as the default view. + * Create a FlutterViewMockProvider with the provided view as the default view. */ - (nonnull instancetype)initWithDefaultView:(nonnull FlutterView*)view; @end -@implementation FlutterViewMockProviderMetal +@implementation FlutterViewMockProvider - (nonnull instancetype)initWithDefaultView:(nonnull FlutterView*)view { self = [super init]; @@ -43,8 +43,7 @@ - (nullable FlutterView*)getView:(uint64_t)viewId { id MockViewProvider() { FlutterView* viewMock = OCMClassMock([FlutterView class]); - FlutterMetalRenderBackingStore* backingStoreMock = - OCMClassMock([FlutterMetalRenderBackingStore class]); + FlutterRenderBackingStore* backingStoreMock = OCMClassMock([FlutterRenderBackingStore class]); __block id textureMock = OCMProtocolMock(@protocol(MTLTexture)); OCMStub([backingStoreMock texture]).andReturn(textureMock); @@ -58,7 +57,7 @@ - (nullable FlutterView*)getView:(uint64_t)viewId { }) .andReturn(backingStoreMock); - return [[FlutterViewMockProviderMetal alloc] initWithDefaultView:viewMock]; + return [[FlutterViewMockProvider alloc] initWithDefaultView:viewMock]; } } // namespace diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEmbedderExternalTextureUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterEmbedderExternalTextureTest.mm similarity index 100% rename from shell/platform/darwin/macos/framework/Source/FlutterEmbedderExternalTextureUnittests.mm rename to shell/platform/darwin/macos/framework/Source/FlutterEmbedderExternalTextureTest.mm diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.mm b/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.mm index 1da401c5e7628..5854bb02f35f6 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.mm @@ -285,7 +285,7 @@ - (void)resolveTo:(BOOL)handled; * Only set in debug mode. Nil in release mode, or if the callback has not been * handled. */ -@property(nonatomic) NSString* debugHandleSource; +@property(nonatomic, copy) NSString* debugHandleSource; @end @implementation FlutterKeyCallbackGuard { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponderUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponderTest.mm similarity index 100% rename from shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponderUnittests.mm rename to shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponderTest.mm diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 47f9ca39aed73..19ed29aa1171c 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -73,6 +73,13 @@ - (instancetype)initWithConnection:(NSNumber*)connection */ @interface FlutterEngine () +/** + * A mutable array that holds one bool value that determines if responses to platform messages are + * clear to execute. This value should be read or written only inside of a synchronized block and + * will return `NO` after the FlutterEngine has been dealloc'd. + */ +@property(nonatomic, strong) NSMutableArray* isResponseValid; + /** * Sends the list of user-preferred locales to the Flutter engine. */ @@ -242,6 +249,8 @@ - (instancetype)initWithName:(NSString*)labelPrefix _allowHeadlessExecution = allowHeadlessExecution; _semanticsEnabled = NO; _viewProvider = [[FlutterViewEngineProvider alloc] initWithEngine:self]; + _isResponseValid = [[NSMutableArray alloc] initWithCapacity:1]; + [_isResponseValid addObject:@YES]; _embedderAPI.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&_embedderAPI); @@ -262,6 +271,10 @@ - (instancetype)initWithName:(NSString*)labelPrefix } - (void)dealloc { + @synchronized(_isResponseValid) { + [_isResponseValid removeAllObjects]; + [_isResponseValid addObject:@NO]; + } [self shutDownEngine]; if (_aotData) { _embedderAPI.CollectAOTData(_aotData); @@ -639,17 +652,25 @@ - (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message { } NSString* channel = @(message->channel); __block const FlutterPlatformMessageResponseHandle* responseHandle = message->response_handle; - + __block FlutterEngine* weakSelf = self; + NSMutableArray* isResponseValid = self.isResponseValid; + FlutterEngineSendPlatformMessageResponseFnPtr sendPlatformMessageResponse = + _embedderAPI.SendPlatformMessageResponse; FlutterBinaryReply binaryResponseHandler = ^(NSData* response) { - if (responseHandle) { - _embedderAPI.SendPlatformMessageResponse(self->_engine, responseHandle, - static_cast(response.bytes), - response.length); - responseHandle = NULL; - } else { - NSLog(@"Error: Message responses can be sent only once. Ignoring duplicate response " - "on channel '%@'.", - channel); + @synchronized(isResponseValid) { + if (![isResponseValid[0] boolValue]) { + // Ignore, engine was killed. + return; + } + if (responseHandle) { + sendPlatformMessageResponse(weakSelf->_engine, responseHandle, + static_cast(response.bytes), response.length); + responseHandle = NULL; + } else { + NSLog(@"Error: Message responses can be sent only once. Ignoring duplicate response " + "on channel '%@'.", + channel); + } } }; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index e6a96d9adf275..143b05b7ced8e 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -614,6 +614,48 @@ @interface FlutterEngine (Test) EXPECT_TRUE(value); } +TEST_F(FlutterEngineTest, ResponseAfterEngineDied) { + FlutterEngine* engine = GetFlutterEngine(); + FlutterBasicMessageChannel* channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"foo" + binaryMessenger:engine.binaryMessenger + codec:[FlutterStandardMessageCodec sharedInstance]]; + __block BOOL didCallCallback = NO; + [channel setMessageHandler:^(id message, FlutterReply callback) { + ShutDownEngine(); + callback(nil); + didCallCallback = YES; + }]; + EXPECT_TRUE([engine runWithEntrypoint:@"sendFooMessage"]); + engine = nil; + + while (!didCallCallback) { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } +} + +TEST_F(FlutterEngineTest, ResponseFromBackgroundThread) { + FlutterEngine* engine = GetFlutterEngine(); + FlutterBasicMessageChannel* channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"foo" + binaryMessenger:engine.binaryMessenger + codec:[FlutterStandardMessageCodec sharedInstance]]; + __block BOOL didCallCallback = NO; + [channel setMessageHandler:^(id message, FlutterReply callback) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + callback(nil); + dispatch_async(dispatch_get_main_queue(), ^{ + didCallCallback = YES; + }); + }); + }]; + EXPECT_TRUE([engine runWithEntrypoint:@"sendFooMessage"]); + + while (!didCallCallback) { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } +} + } // namespace flutter::testing // NOLINTEND(clang-analyzer-core.StackAddressEscape) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h b/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h index c2396bc0b538a..b52524cd9dec5 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h @@ -23,6 +23,8 @@ class FlutterEngineTest : public ::testing::Test { static void IsolateCreateCallback(void* user_data); + void ShutDownEngine(); + private: inline static std::shared_ptr native_resolver_; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.mm index 8bc57273ae4b5..8a535aa5e22e1 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.mm @@ -31,6 +31,11 @@ native_resolver_.reset(); } +void FlutterEngineTest::ShutDownEngine() { + [engine_ shutDownEngine]; + engine_ = nil; +} + void FlutterEngineTest::IsolateCreateCallback(void* user_data) { native_resolver_->SetNativeResolverForIsolate(); } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterKeyPrimaryResponder.h b/shell/platform/darwin/macos/framework/Source/FlutterKeyPrimaryResponder.h index 8fa599f14ea1f..b61c790028a3b 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterKeyPrimaryResponder.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterKeyPrimaryResponder.h @@ -31,6 +31,6 @@ typedef void (^FlutterAsyncKeyCallback)(BOOL handled); * deriving logical keys. */ @required -@property(nonatomic) NSMutableDictionary* _Nullable layoutMap; +@property(nonatomic, nullable, strong) NSMutableDictionary* layoutMap; @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerTest.mm similarity index 99% rename from shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm rename to shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerTest.mm index b5fe0e65626f6..d9b2ba994d7f2 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerTest.mm @@ -211,8 +211,8 @@ - (void)respondTextInputWith:(BOOL)response; - (void)recordCallTypesTo:(nonnull NSMutableArray*)typeStorage forTypes:(uint32_t)typeMask; -@property(nonatomic) FlutterKeyboardManager* manager; -@property(nonatomic) NSResponder* nextResponder; +@property(readonly, nonatomic, strong) FlutterKeyboardManager* manager; +@property(nonatomic, nullable, strong) NSResponder* nextResponder; #pragma mark - Private diff --git a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm index d02de6c5c8eab..996e613dba926 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm @@ -95,8 +95,7 @@ - (FlutterMetalTexture)createTextureForView:(uint64_t)viewId size:(CGSize)size { // FlutterMetalTexture has texture `null`, therefore is discarded. return FlutterMetalTexture{}; } - FlutterMetalRenderBackingStore* backingStore = - (FlutterMetalRenderBackingStore*)[view backingStoreForSize:size]; + FlutterRenderBackingStore* backingStore = [view backingStoreForSize:size]; id texture = backingStore.texture; FlutterMetalTexture embedderTexture; embedderTexture.struct_size = sizeof(FlutterMetalTexture); diff --git a/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.h b/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.h index eb8ae31d5963a..00a93ac213078 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.h @@ -10,10 +10,16 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h" /** - * Represents a buffer that can be resized. + * Provides resizable buffers backed by a MTLTexture. */ -@protocol FlutterResizableBackingStoreProvider +@interface FlutterResizableBackingStoreProvider : NSObject +/** + * Creates a resizable backing store provider for the given CAMetalLayer. + */ +- (nonnull instancetype)initWithDevice:(nonnull id)device + commandQueue:(nonnull id)commandQueue + layer:(nonnull CALayer*)layer; /** * Notify of the required backing store size updates. Called during window resize. */ @@ -25,19 +31,3 @@ - (nonnull FlutterRenderBackingStore*)backingStore; @end - -/** - * Metal-backed FlutterResizableBackingStoreProvider. Backing store in this context implies a - * MTLTexture. - */ -@interface FlutterMetalResizableBackingStoreProvider - : NSObject - -/** - * Creates a resizable backing store provider for the given CAMetalLayer. - */ -- (nonnull instancetype)initWithDevice:(nonnull id)device - commandQueue:(nonnull id)commandQueue - layer:(nonnull CALayer*)layer; - -@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.mm b/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.mm index fc07530c375a0..436d41af68f15 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.mm @@ -8,7 +8,7 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h" -@implementation FlutterMetalResizableBackingStoreProvider { +@implementation FlutterResizableBackingStoreProvider { id _device; id _commandQueue; FlutterSurfaceManager* _surfaceManager; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm index 06d0e5f234877..d3d612fd294c8 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm @@ -143,7 +143,7 @@ - (void)cancelIdle { - (nonnull FlutterRenderBackingStore*)renderBuffer { [self ensureBackBuffer]; id texture = _textures[kFlutterSurfaceManagerBackBuffer]; - return [[FlutterMetalRenderBackingStore alloc] initWithTexture:texture]; + return [[FlutterRenderBackingStore alloc] initWithTexture:texture]; } - (id)createTextureForSurface:(FlutterIOSurfaceHolder*)surface size:(CGSize)size { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm index fdcd62f9d7e34..b9e1742abd547 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm @@ -9,13 +9,13 @@ #include "flutter/testing/testing.h" #include "gtest/gtest.h" -@interface TestMetalView : NSView +@interface TestView : NSView - (nonnull instancetype)init; @end -@implementation TestMetalView +@implementation TestView - (instancetype)init { self = [super initWithFrame:NSZeroRect]; @@ -32,7 +32,7 @@ - (instancetype)init { static FlutterSurfaceManager* CreateSurfaceManager() { id device = MTLCreateSystemDefaultDevice(); id commandQueue = [device newCommandQueue]; - TestMetalView* metalView = [[TestMetalView alloc] init]; + TestView* metalView = [[TestView alloc] init]; CALayer* layer = reinterpret_cast(metalView.layer); return [[FlutterSurfaceManager alloc] initWithDevice:device commandQueue:commandQueue @@ -43,8 +43,7 @@ - (instancetype)init { FlutterSurfaceManager* surfaceManager = CreateSurfaceManager(); CGSize size = CGSizeMake(100, 50); [surfaceManager ensureSurfaceSize:size]; - id texture = - (reinterpret_cast([surfaceManager renderBuffer])).texture; + id texture = [surfaceManager renderBuffer].texture; CGSize textureSize = CGSizeMake(texture.width, texture.height); ASSERT_TRUE(CGSizeEqualToSize(size, textureSize)); } @@ -55,8 +54,7 @@ - (instancetype)init { [surfaceManager ensureSurfaceSize:size]; [surfaceManager renderBuffer]; // make sure we have back buffer [surfaceManager swapBuffers]; - id texture = - (reinterpret_cast([surfaceManager renderBuffer])).texture; + id texture = [surfaceManager renderBuffer].texture; CGSize textureSize = CGSizeMake(texture.width, texture.height); ASSERT_TRUE(CGSizeEqualToSize(size, textureSize)); } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm index 0a1d2a2b70876..9f4a39d4b3818 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm @@ -12,9 +12,13 @@ #import #import "flutter/testing/testing.h" +@interface FlutterTextField (Testing) +- (void)setPlatformNode:(flutter::FlutterTextPlatformNode*)node; +@end + @interface FlutterTextFieldMock : FlutterTextField -@property(nonatomic) NSString* lastUpdatedString; +@property(nonatomic, nullable, copy) NSString* lastUpdatedString; @property(nonatomic) NSRange lastUpdatedSelection; @end @@ -1434,37 +1438,47 @@ - (bool)testSelectorsAreForwardedToFramework { node_data.SetValue("initial text"); ax_node.SetData(node_data); delegate.Init(engine.accessibilityBridge, &ax_node); - FlutterTextPlatformNode text_platform_node(&delegate, viewController); + { + FlutterTextPlatformNode text_platform_node(&delegate, viewController); + + FlutterTextFieldMock* mockTextField = + [[FlutterTextFieldMock alloc] initWithPlatformNode:&text_platform_node + fieldEditor:viewController.textInputPlugin]; + [viewController.view addSubview:mockTextField]; + [mockTextField startEditing]; + + NSDictionary* arguments = @{ + @"inputAction" : @"action", + @"inputType" : @{@"name" : @"inputName"}, + }; + FlutterMethodCall* methodCall = + [FlutterMethodCall methodCallWithMethodName:@"TextInput.setClient" + arguments:@[ @(1), arguments ]]; + FlutterResult result = ^(id result) { + }; + [viewController.textInputPlugin handleMethodCall:methodCall result:result]; + + arguments = @{ + @"text" : @"new text", + @"selectionBase" : @(1), + @"selectionExtent" : @(2), + @"composingBase" : @(-1), + @"composingExtent" : @(-1), + }; - FlutterTextFieldMock* mockTextField = - [[FlutterTextFieldMock alloc] initWithPlatformNode:&text_platform_node - fieldEditor:viewController.textInputPlugin]; - [viewController.view addSubview:mockTextField]; - [mockTextField startEditing]; + methodCall = [FlutterMethodCall methodCallWithMethodName:@"TextInput.setEditingState" + arguments:arguments]; + [viewController.textInputPlugin handleMethodCall:methodCall result:result]; + EXPECT_EQ([mockTextField.lastUpdatedString isEqualToString:@"new text"], YES); + EXPECT_EQ(NSEqualRanges(mockTextField.lastUpdatedSelection, NSMakeRange(1, 1)), YES); - NSDictionary* arguments = @{ - @"inputAction" : @"action", - @"inputType" : @{@"name" : @"inputName"}, - }; - FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"TextInput.setClient" - arguments:@[ @(1), arguments ]]; - FlutterResult result = ^(id result) { - }; - [viewController.textInputPlugin handleMethodCall:methodCall result:result]; - - arguments = @{ - @"text" : @"new text", - @"selectionBase" : @(1), - @"selectionExtent" : @(2), - @"composingBase" : @(-1), - @"composingExtent" : @(-1), - }; + // This blocks the FlutterTextFieldMock, which is held onto by the main event + // loop, from crashing. + [mockTextField setPlatformNode:nil]; + } - methodCall = [FlutterMethodCall methodCallWithMethodName:@"TextInput.setEditingState" - arguments:arguments]; - [viewController.textInputPlugin handleMethodCall:methodCall result:result]; - EXPECT_EQ([mockTextField.lastUpdatedString isEqualToString:@"new text"], YES); - EXPECT_EQ(NSEqualRanges(mockTextField.lastUpdatedSelection, NSMakeRange(1, 1)), YES); + // This verifies that clearing the platform node works. + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; } TEST(FlutterTextInputPluginTest, CanNotBecomeResponderIfNoViewController) { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.mm b/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.mm index 75fecca90163c..7aa874bbc905c 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.mm @@ -91,12 +91,18 @@ - (void)updateString:(NSString*)string withSelection:(NSRange)selection { #pragma mark - NSView - (NSRect)frame { + if (!_node) { + return NSZeroRect; + } return _node->GetFrame(); } #pragma mark - NSAccessibilityProtocol - (void)setAccessibilityFocused:(BOOL)isFocused { + if (!_node) { + return; + } [super setAccessibilityFocused:isFocused]; ui::AXActionData data; data.action = isFocused ? ax::mojom::Action::kFocus : ax::mojom::Action::kBlur; @@ -110,6 +116,9 @@ - (void)startEditing { if (self.currentEditor == _plugin) { return; } + if (!_node) { + return; + } // Selecting text seems to be the only way to make the field editor // current editor. [self selectText:self]; @@ -133,6 +142,10 @@ - (void)startEditing { [self updateString:textValue withSelection:selection]; } +- (void)setPlatformNode:(flutter::FlutterTextPlatformNode*)node { + _node = node; +} + #pragma mark - NSObject - (void)dealloc { @@ -159,6 +172,7 @@ - (void)dealloc { } FlutterTextPlatformNode::~FlutterTextPlatformNode() { + [appkit_text_field_ setPlatformNode:nil]; EnsureDetachedFromView(); } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObjectTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObjectTest.mm index 3032f5cc054af..287b12713c24a 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObjectTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObjectTest.mm @@ -27,39 +27,48 @@ TEST(FlutterTextInputSemanticsObjectTest, DoesInitialize) { FlutterEngine* engine = CreateTestEngine(); - NSString* fixtures = @(testing::GetFixturesPath()); - FlutterDartProject* project = [[FlutterDartProject alloc] - initWithAssetsPath:fixtures - ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; - FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; - [viewController loadView]; - [engine setViewController:viewController]; - // Create a NSWindow so that the native text field can become first responder. - NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600) - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - window.contentView = viewController.view; + { + NSString* fixtures = @(testing::GetFixturesPath()); + FlutterDartProject* project = [[FlutterDartProject alloc] + initWithAssetsPath:fixtures + ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; + [viewController loadView]; + [engine setViewController:viewController]; + // Create a NSWindow so that the native text field can become first responder. + NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600) + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + window.contentView = viewController.view; + + engine.semanticsEnabled = YES; - engine.semanticsEnabled = YES; + auto bridge = engine.accessibilityBridge.lock(); + FlutterPlatformNodeDelegateMac delegate(bridge, viewController); + ui::AXTree tree; + ui::AXNode ax_node(&tree, nullptr, 0, 0); + ui::AXNodeData node_data; + node_data.SetValue("initial text"); + ax_node.SetData(node_data); + delegate.Init(engine.accessibilityBridge, &ax_node); + // Verify that a FlutterTextField is attached to the view. + FlutterTextPlatformNode text_platform_node(&delegate, viewController); + id native_accessibility = text_platform_node.GetNativeViewAccessible(); + EXPECT_TRUE([native_accessibility isKindOfClass:[FlutterTextField class]]); + auto subviews = [viewController.view subviews]; + EXPECT_EQ([subviews count], 2u); + EXPECT_TRUE([subviews[0] isKindOfClass:[FlutterTextField class]]); + FlutterTextField* nativeTextField = subviews[0]; + EXPECT_EQ(text_platform_node.GetNativeViewAccessible(), nativeTextField); + } - auto bridge = engine.accessibilityBridge.lock(); - FlutterPlatformNodeDelegateMac delegate(bridge, viewController); - ui::AXTree tree; - ui::AXNode ax_node(&tree, nullptr, 0, 0); - ui::AXNodeData node_data; - node_data.SetValue("initial text"); - ax_node.SetData(node_data); - delegate.Init(engine.accessibilityBridge, &ax_node); - // Verify that a FlutterTextField is attached to the view. - FlutterTextPlatformNode text_platform_node(&delegate, viewController); - id native_accessibility = text_platform_node.GetNativeViewAccessible(); - EXPECT_TRUE([native_accessibility isKindOfClass:[FlutterTextField class]]); - auto subviews = [viewController.view subviews]; - EXPECT_EQ([subviews count], 2u); - EXPECT_TRUE([subviews[0] isKindOfClass:[FlutterTextField class]]); - FlutterTextField* nativeTextField = subviews[0]; - EXPECT_EQ(text_platform_node.GetNativeViewAccessible(), nativeTextField); + [engine shutDownEngine]; + engine = nil; + // Pump the event loop to make sure no stray nodes cause crashes after the + // engine has been destroyed. + // From issue: https://github.com/flutter/flutter/issues/115599 + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; } } // namespace flutter::testing diff --git a/shell/platform/darwin/macos/framework/Source/FlutterView.mm b/shell/platform/darwin/macos/framework/Source/FlutterView.mm index 60f3b0c3f70d6..8a92b9f5fbb59 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterView.mm @@ -12,7 +12,7 @@ @interface FlutterView () { __weak id _reshapeListener; FlutterResizeSynchronizer* _resizeSynchronizer; - id _resizableBackingStoreProvider; + FlutterResizableBackingStoreProvider* _resizableBackingStoreProvider; } @end @@ -29,9 +29,9 @@ - (instancetype)initWithMTLDevice:(id)device [self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawDuringViewResize]; _reshapeListener = reshapeListener; _resizableBackingStoreProvider = - [[FlutterMetalResizableBackingStoreProvider alloc] initWithDevice:device - commandQueue:commandQueue - layer:self.layer]; + [[FlutterResizableBackingStoreProvider alloc] initWithDevice:device + commandQueue:commandQueue + layer:self.layer]; _resizeSynchronizer = [[FlutterResizeSynchronizer alloc] initWithDelegate:_resizableBackingStoreProvider]; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm similarity index 100% rename from shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderUnittests.mm rename to shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm diff --git a/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart b/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart index afdc3275e9618..835588ff354ac 100644 --- a/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart +++ b/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:io'; +import 'dart:typed_data'; import 'dart:ui'; @pragma('vm:external-name', 'SignalNativeTest') @@ -63,3 +64,8 @@ void backgroundTest() { PlatformDispatcher.instance.views.first.render(SceneBuilder().build()); signalNativeTest(); // should look black } + +@pragma('vm:entry-point') +void sendFooMessage() { + PlatformDispatcher.instance.sendPlatformMessage('foo', null, (ByteData? result) {}); +} diff --git a/shell/platform/embedder/tests/embedder_unittests_gl.cc b/shell/platform/embedder/tests/embedder_unittests_gl.cc index 5efa27878e968..a7018859d1d47 100644 --- a/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -4018,7 +4018,7 @@ TEST_F(EmbedderTest, ExternalTextureGLRefreshedTooOften) { TestGLSurface surface(SkISize::Make(100, 100)); auto context = surface.GetGrContext(); - typedef void (*glGenTexturesProc)(uint32_t n, uint32_t* textures); + typedef void (*glGenTexturesProc)(uint32_t n, uint32_t * textures); glGenTexturesProc glGenTextures; glGenTextures = reinterpret_cast( diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc index f31aecb683d03..617f22bd46277 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flatland_external_view_embedder.h" +#include #include #include "flutter/fml/trace_event.h" @@ -17,6 +18,24 @@ namespace { // overflows on operations (like FLT_MAX would). constexpr float kMaxHitRegionSize = 1'000'000.f; +void AttachClipTransformChild( + FlatlandConnection* flatland, + FlatlandExternalViewEmbedder::ClipTransform* parent_clip_transform, + const fuchsia::ui::composition::TransformId& child_transform_id) { + flatland->flatland()->AddChild(parent_clip_transform->transform_id, + child_transform_id); + parent_clip_transform->children.push_back(child_transform_id); +} + +void DetachClipTransformChildren( + FlatlandConnection* flatland, + FlatlandExternalViewEmbedder::ClipTransform* clip_transform) { + for (auto& child : clip_transform->children) { + flatland->flatland()->RemoveChild(clip_transform->transform_id, child); + } + clip_transform->children.clear(); +} + } // namespace FlatlandExternalViewEmbedder::FlatlandExternalViewEmbedder( @@ -93,8 +112,9 @@ void FlatlandExternalViewEmbedder::PrerollCompositeEmbeddedView( zx_handle_t handle = static_cast(view_id); FML_CHECK(frame_layers_.count(handle) == 0); - frame_layers_.emplace(std::make_pair(EmbedderLayerId{handle}, - EmbedderLayer(frame_size_, *params))); + frame_layers_.emplace(std::make_pair( + EmbedderLayerId{handle}, + EmbedderLayer(frame_size_, *params, flutter::RTreeFactory()))); frame_composition_order_.push_back(handle); } @@ -125,8 +145,9 @@ void FlatlandExternalViewEmbedder::BeginFrame( frame_dpr_ = device_pixel_ratio; // Create the root layer. - frame_layers_.emplace( - std::make_pair(kRootLayerId, EmbedderLayer(frame_size, std::nullopt))); + frame_layers_.emplace(std::make_pair( + kRootLayerId, + EmbedderLayer(frame_size, std::nullopt, flutter::RTreeFactory()))); frame_composition_order_.push_back(kRootLayerId); } @@ -193,6 +214,19 @@ void FlatlandExternalViewEmbedder::SubmitFrame( } } + // Finish recording SkPictures. + { + TRACE_EVENT0("flutter", "FinishRecordingPictures"); + + for (const auto& surface_index : frame_surface_indices) { + const auto& layer = frame_layers_.find(surface_index.first); + FML_CHECK(layer != frame_layers_.end()); + layer->second.picture = + layer->second.recorder->finishRecordingAsPicture(); + FML_CHECK(layer->second.picture != nullptr); + } + } + // Submit layers and platform views to Scenic in composition order. { TRACE_EVENT0("flutter", "SubmitLayers"); @@ -248,7 +282,6 @@ void FlatlandExternalViewEmbedder::SubmitFrame( viewport.transform_id, {static_cast(view_mutators.transform.getTranslateX()), static_cast(view_mutators.transform.getTranslateY())}); - flatland_->flatland()->SetScale( viewport.transform_id, {view_mutators.transform.getScaleX(), view_mutators.transform.getScaleY()}); @@ -256,7 +289,54 @@ void FlatlandExternalViewEmbedder::SubmitFrame( } // TODO(fxbug.dev/94000): Set HitTestBehavior. - // TODO(fxbug.dev/94000): Set ClipRegions. + + // Set clip regions. + if (view_mutators.clips != viewport.mutators.clips) { + // Expand the clip_transforms array to fit any new transforms. + while (viewport.clip_transforms.size() < view_mutators.clips.size()) { + ClipTransform clip_transform; + clip_transform.transform_id = flatland_->NextTransformId(); + flatland_->flatland()->CreateTransform(clip_transform.transform_id); + viewport.clip_transforms.emplace_back(std::move(clip_transform)); + } + FML_CHECK(viewport.clip_transforms.size() >= + view_mutators.clips.size()); + + // Adjust and re-parent all clip transforms. + for (auto& clip_transform : viewport.clip_transforms) { + DetachClipTransformChildren(flatland_.get(), &clip_transform); + } + + for (size_t c = 0; c < view_mutators.clips.size(); c++) { + const SkMatrix& clip_matrix = view_mutators.clips[c].transform; + const SkRect& clip_rect = view_mutators.clips[c].rect; + + flatland_->flatland()->SetTranslation( + viewport.clip_transforms[c].transform_id, + {static_cast(clip_matrix.getTranslateX()), + static_cast(clip_matrix.getTranslateY())}); + flatland_->flatland()->SetScale( + viewport.clip_transforms[c].transform_id, + {clip_matrix.getScaleX(), clip_matrix.getScaleY()}); + fuchsia::math::Rect rect = { + static_cast(clip_rect.x()), + static_cast(clip_rect.y()), + static_cast(clip_rect.width()), + static_cast(clip_rect.height())}; + flatland_->flatland()->SetClipBoundary( + viewport.clip_transforms[c].transform_id, + std::make_unique(std::move(rect))); + + const auto child_transform_id = + c != (view_mutators.clips.size() - 1) + ? viewport.clip_transforms[c + 1].transform_id + : viewport.transform_id; + AttachClipTransformChild(flatland_.get(), + &(viewport.clip_transforms[c]), + child_transform_id); + } + viewport.mutators.clips = view_mutators.clips; + } // Set opacity. if (view_mutators.opacity != viewport.mutators.opacity) { @@ -284,9 +364,13 @@ void FlatlandExternalViewEmbedder::SubmitFrame( } // Attach the FlatlandView to the main scene graph. + const auto main_child_transform = + viewport.mutators.clips.empty() + ? viewport.transform_id + : viewport.clip_transforms[0].transform_id; flatland_->flatland()->AddChild(root_transform_id_, - viewport.transform_id); - child_transforms_.emplace_back(viewport.transform_id); + main_child_transform); + child_transforms_.emplace_back(main_child_transform); } // Acquire the surface associated with the layer. @@ -334,30 +418,43 @@ void FlatlandExternalViewEmbedder::SubmitFrame( ? fuchsia::ui::composition::BlendMode::SRC : fuchsia::ui::composition::BlendMode::SRC_OVER); + // Set hit regions for this layer; these hit regions correspond to the + // portions of the layer on which skia drew content. + { + FML_CHECK(layer->second.rtree); + std::list intersection_rects = + layer->second.rtree->searchNonOverlappingDrawnRects( + SkRect::Make(layer->second.surface_size)); + + std::vector hit_regions; + for (const SkRect& rect : intersection_rects) { + hit_regions.emplace_back(); + auto& new_hit_region = hit_regions.back(); + new_hit_region.region.x = rect.x(); + new_hit_region.region.y = rect.y(); + new_hit_region.region.width = rect.width(); + new_hit_region.region.height = rect.height(); + new_hit_region.hit_test = + fuchsia::ui::composition::HitTestInteraction::DEFAULT; + } + + flatland_->flatland()->SetHitRegions( + flatland_layers_[flatland_layer_index].transform_id, + std::move(hit_regions)); + } + // Attach the FlatlandLayer to the main scene graph. flatland_->flatland()->AddChild( root_transform_id_, flatland_layers_[flatland_layer_index].transform_id); child_transforms_.emplace_back( flatland_layers_[flatland_layer_index].transform_id); - - // Attach full-screen hit testing shield. Note that since the hit-region - // may be transformed (translated, rotated), we do not want to set - // width/height to FLT_MAX. This will cause a numeric overflow. - flatland_->flatland()->SetHitRegions( - flatland_layers_[flatland_layer_index].transform_id, - {{{0, 0, kMaxHitRegionSize, kMaxHitRegionSize}, - fuchsia::ui::composition::HitTestInteraction:: - SEMANTICALLY_INVISIBLE}}); } // Reset for the next pass: flatland_layer_index++; } - // TODO(fxbug.dev/104956): Setting per-layer overlay hit region for Flatland - // external view embedder should match with what is being done in GFX - // external view embedder. // Set up the input interceptor at the top of the // scene, if applicable. It will capture all input, and any unwanted input // will be reinjected into embedded views. @@ -396,13 +493,10 @@ void FlatlandExternalViewEmbedder::SubmitFrame( const auto& layer = frame_layers_.find(surface_index.first); FML_CHECK(layer != frame_layers_.end()); - sk_sp picture = - layer->second.recorder->finishRecordingAsPicture(); - FML_CHECK(picture != nullptr); canvas->setMatrix(SkMatrix::I()); canvas->clear(SK_ColorTRANSPARENT); - canvas->drawPicture(picture); + canvas->drawPicture(layer->second.picture); canvas->flush(); } } @@ -460,19 +554,29 @@ void FlatlandExternalViewEmbedder::DestroyView( auto viewport_id = flatland_view->second.viewport_id; auto transform_id = flatland_view->second.transform_id; + auto& clip_transforms = flatland_view->second.clip_transforms; if (!flatland_view->second.pending_create_viewport_callback) { flatland_->flatland()->ReleaseViewport(viewport_id, [](auto) {}); } - auto itr = - std::find_if(child_transforms_.begin(), child_transforms_.end(), - [transform_id](fuchsia::ui::composition::TransformId id) { - return id.value == transform_id.value; - }); + auto itr = std::find_if( + child_transforms_.begin(), child_transforms_.end(), + [transform_id, + &clip_transforms](fuchsia::ui::composition::TransformId id) { + return id.value == transform_id.value || + (!clip_transforms.empty() && + (id.value == clip_transforms[0].transform_id.value)); + }); if (itr != child_transforms_.end()) { - flatland_->flatland()->RemoveChild(root_transform_id_, transform_id); + flatland_->flatland()->RemoveChild(root_transform_id_, *itr); child_transforms_.erase(itr); } + for (auto& clip_transform : clip_transforms) { + DetachClipTransformChildren(flatland_.get(), &clip_transform); + } flatland_->flatland()->ReleaseTransform(transform_id); + for (auto& clip_transform : clip_transforms) { + flatland_->flatland()->ReleaseTransform(clip_transform.transform_id); + } flatland_views_.erase(flatland_view); on_view_unbound(viewport_id); diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h index 0600b598c1351..b12ef0f8c1074 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h @@ -17,6 +17,7 @@ #include #include "flutter/flow/embedded_views.h" +#include "flutter/flow/rtree.h" #include "flutter/fml/logging.h" #include "flutter/fml/macros.h" #include "flutter/shell/common/canvas_spy.h" @@ -113,6 +114,12 @@ class FlatlandExternalViewEmbedder final bool hit_testable, bool focusable); + // Holds the clip transform that may be applied on a FlatlandView. + struct ClipTransform { + fuchsia::ui::composition::TransformId transform_id; + std::vector children; + }; + private: void Reset(); // Reset state for a new frame. @@ -144,23 +151,35 @@ class FlatlandExternalViewEmbedder final struct EmbedderLayer { EmbedderLayer(const SkISize& frame_size, - std::optional view_params) - : embedded_view_params(std::move(view_params)), + std::optional view_params, + flutter::RTreeFactory rtree_factory) + : rtree(rtree_factory.getInstance()), + embedded_view_params(std::move(view_params)), recorder(std::make_unique()), canvas_spy(std::make_unique( - recorder->beginRecording(frame_size.width(), - frame_size.height()))), - surface_size(frame_size) {} + recorder->beginRecording(SkRect::Make(frame_size), + &rtree_factory))), + surface_size(frame_size), + picture(nullptr) {} + + // Records paint operations applied to this layer's `SkCanvas`. + // These records are used to determine which portions of this layer + // contain content. The embedder propagates this information to scenic, so + // that scenic can accurately decide which portions of this layer may + // interact with input. + sk_sp rtree; std::optional embedded_view_params; std::unique_ptr recorder; std::unique_ptr canvas_spy; SkISize surface_size; + sk_sp picture; }; using EmbedderLayerId = std::optional; constexpr static EmbedderLayerId kRootLayerId = EmbedderLayerId{}; struct FlatlandView { + std::vector clip_transforms; fuchsia::ui::composition::TransformId transform_id; fuchsia::ui::composition::ContentId viewport_id; ViewMutators mutators; diff --git a/shell/platform/fuchsia/flutter/flatland_platform_view.cc b/shell/platform/fuchsia/flutter/flatland_platform_view.cc index 0373c6ace6f23..6766c26da1846 100644 --- a/shell/platform/fuchsia/flutter/flatland_platform_view.cc +++ b/shell/platform/fuchsia/flutter/flatland_platform_view.cc @@ -75,14 +75,14 @@ void FlatlandPlatformView::OnGetLayout( view_logical_size_ = {static_cast(info.logical_size().width), static_cast(info.logical_size().height)}; - float pixel_ratio = 1.0f; if (info.has_device_pixel_ratio()) { // Flatland returns a Vec2 for DPR but both values should be identical. FML_DCHECK(info.device_pixel_ratio().x == info.device_pixel_ratio().y); view_pixel_ratio_ = info.device_pixel_ratio().x; - pixel_ratio = *view_pixel_ratio_; } + float pixel_ratio = view_pixel_ratio_ ? *view_pixel_ratio_ : 1.0f; + SetViewportMetrics({ pixel_ratio, // device_pixel_ratio std::round(view_logical_size_.value()[0] * diff --git a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc index a55d89aca2bcd..4c782089df38e 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc +++ b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc @@ -850,7 +850,7 @@ void FakeFlatland::SetHitRegions( auto& transform = found_transform->second; FML_CHECK(transform); - transform->num_hit_regions = regions.size(); + transform->hit_regions = std::move(regions); } void FakeFlatland::Clear() { diff --git a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc index a265241f4d781..777344a36f5df 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc +++ b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc @@ -72,7 +72,7 @@ std::shared_ptr CloneFakeTransform( .children = CloneFakeTransformVector( transform->children, transform_cache), .content = CloneFakeContent(transform->content), - .num_hit_regions = transform->num_hit_regions, + .hit_regions = transform->hit_regions, })); FML_CHECK(success); @@ -136,7 +136,7 @@ bool FakeTransform::operator==(const FakeTransform& other) const { return id == other.id && translation == other.translation && *clip_bounds == *other.clip_bounds && orientation == other.orientation && children == other.children && - content == other.content && num_hit_regions == other.num_hit_regions; + content == other.content && hit_regions == other.hit_regions; } bool FakeGraph::operator==(const FakeGraph& other) const { diff --git a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h index cd2170c3b58f3..40f1648707e10 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h +++ b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -98,6 +99,41 @@ inline bool operator==(const fuchsia::ui::composition::ImageProperties& a, return size_equal; } +inline bool operator==(const fuchsia::ui::composition::HitRegion& a, + const fuchsia::ui::composition::HitRegion& b) { + return a.region == b.region && a.hit_test == b.hit_test; +} + +inline bool operator!=(const fuchsia::ui::composition::HitRegion& a, + const fuchsia::ui::composition::HitRegion& b) { + return !(a == b); +} + +inline bool operator==( + const std::vector& a, + const std::vector& b) { + if (a.size() != b.size()) + return false; + + for (size_t i = 0; i < a.size(); ++i) { + if (a[i] != b[i]) { + return false; + } + } + + return true; +} + +inline bool operator==(const std::optional& a, + const std::optional& b) { + if (a.has_value() != b.has_value()) { + return false; + } + if (!a.has_value()) { + } + return a.value() == b.value(); +} + namespace flutter_runner::testing { constexpr static fuchsia::ui::composition::TransformId kInvalidTransformId{0}; @@ -194,7 +230,7 @@ struct FakeTransform { std::vector> children; std::shared_ptr content; - size_t num_hit_regions; + std::vector hit_regions; }; struct FakeGraph { diff --git a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_session.cc b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_session.cc index 294481959c9a1..133360acd21ac 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_session.cc +++ b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_session.cc @@ -108,7 +108,7 @@ void FakeSession::Present(uint64_t presentation_time, ApplyCommands(); PresentHandler present_handler = - present_handler_ ? present_handler_ : [](auto... args) -> auto{ + present_handler_ ? present_handler_ : [](auto... args) -> auto { return fuchsia::images::PresentationInfo{}; }; @@ -124,7 +124,7 @@ void FakeSession::Present2(fuchsia::ui::scenic::Present2Args args, ApplyCommands(); Present2Handler present2_handler = - present2_handler_ ? present2_handler_ : [](auto args) -> auto{ + present2_handler_ ? present2_handler_ : [](auto args) -> auto { return fuchsia::scenic::scheduling::FuturePresentationTimes{ .future_presentations = {}, .remaining_presents_in_flight_allowed = 1, @@ -142,7 +142,7 @@ void FakeSession::RequestPresentationTimes( RequestPresentationTimesCallback callback) { RequestPresentationTimesHandler request_presentation_times_handler = request_presentation_times_handler_ ? request_presentation_times_handler_ - : [](auto args) -> auto{ + : [](auto args) -> auto { return fuchsia::scenic::scheduling::FuturePresentationTimes{ .future_presentations = {}, .remaining_presents_in_flight_allowed = 1, diff --git a/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc b/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc index fac48844c782e..eb9b79d46d111 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc @@ -202,6 +202,15 @@ Matcher IsViewportProperties( inset)); } +Matcher IsHitRegion( + const float x, + const float y, + const float width, + const float height, + const fuchsia::ui::composition::HitTestInteraction hit_test) { + return FieldsAre(FieldsAre(x, y, width, height), hit_test); +} + Matcher IsEmptyGraph() { return FieldsAre(IsEmpty(), IsEmpty(), Eq(nullptr), Eq(std::nullopt)); } @@ -224,7 +233,7 @@ Matcher IsFlutterGraph( /*scale*/ scale, FakeTransform::kDefaultOrientation, /*clip_bounds*/ _, FakeTransform::kDefaultOpacity, /*children*/ ElementsAreArray(layer_matchers), - /*content*/ Eq(nullptr), /*num_hit_regions*/ _)), + /*content*/ Eq(nullptr), /*hit_regions*/ _)), Eq(FakeView{ .view_token = viewport_token_koids.second, .view_ref = view_ref_koids.first, @@ -240,7 +249,8 @@ Matcher IsFlutterGraph( Matcher> IsImageLayer( const fuchsia::math::SizeU& layer_size, fuchsia::ui::composition::BlendMode blend_mode, - size_t num_hit_regions) { + std::vector> + hit_region_matchers) { return Pointee(FieldsAre( /*id*/ _, FakeTransform::kDefaultTranslation, FakeTransform::kDefaultScale, FakeTransform::kDefaultOrientation, @@ -252,7 +262,7 @@ Matcher> IsImageLayer( FakeImage::kDefaultSampleRegion, layer_size, FakeImage::kDefaultOpacity, blend_mode, /*buffer_import_token*/ _, /*vmo_index*/ 0))), - num_hit_regions)); + /* hit_regions*/ ElementsAreArray(hit_region_matchers))); } Matcher> IsViewportLayer( @@ -271,9 +281,22 @@ Matcher> IsViewportLayer( /* id */ _, IsViewportProperties(view_logical_size, view_inset), /* viewport_token */ GetKoids(view_token).second, /* child_view_watcher */ _))), - /*num_hit_regions*/ 0)); + /*hit_regions*/ _)); } +Matcher> IsClipTransformLayer( + const fuchsia::math::Vec& transform_translation, + const fuchsia::math::VecF& transform_scale, + std::optional clip_bounds, + Matcher> viewport_matcher) { + return Pointee(FieldsAre( + /* id */ _, transform_translation, transform_scale, + FakeTransform::kDefaultOrientation, /*clip_bounds*/ clip_bounds, + FakeTransform::kDefaultOpacity, + /*children*/ ElementsAre(viewport_matcher), + /*content*/ _, + /*hit_regions*/ _)); +} fuchsia::ui::composition::OnNextFrameBeginValues WithPresentCredits( uint32_t additional_present_credits) { fuchsia::ui::composition::OnNextFrameBeginValues values; @@ -478,11 +501,21 @@ TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene) { // Pump the message loop. The scene updates should propagate to flatland. loop().RunUntilIdle(); + EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref, - /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, + /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); } TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { @@ -598,10 +631,26 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { fake_flatland().graph(), IsFlutterGraph( parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)}), IsViewportLayer(child_view_token, child_view_size, child_view_inset, {0, 0}, kScale, kOpacityFloat), - IsImageLayer(frame_size, kUpperLayerBlendMode, 1)}, + IsImageLayer( + frame_size, kUpperLayerBlendMode, + {IsHitRegion( + /* x */ 384.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}, {kInvDPR, kInvDPR})); // Destroy the view. The scene graph shouldn't change yet. @@ -611,10 +660,26 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { fake_flatland().graph(), IsFlutterGraph( parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)}), IsViewportLayer(child_view_token, child_view_size, child_view_inset, {0, 0}, kScale, kOpacityFloat), - IsImageLayer(frame_size, kUpperLayerBlendMode, 1)}, + IsImageLayer( + frame_size, kUpperLayerBlendMode, + {IsHitRegion( + /* x */ 384.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}, {kInvDPR, kInvDPR})); // Draw another frame without the view. The scene graph shouldn't change yet. @@ -634,19 +699,289 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { fake_flatland().graph(), IsFlutterGraph( parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)}), IsViewportLayer(child_view_token, child_view_size, child_view_inset, {0, 0}, kScale, kOpacityFloat), - IsImageLayer(frame_size, kUpperLayerBlendMode, 1)}, + IsImageLayer( + frame_size, kUpperLayerBlendMode, + {IsHitRegion( + /* x */ 384.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}, {kInvDPR, kInvDPR})); // Pump the message loop. The scene updates should propagate to flatland. loop().RunUntilIdle(); EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, - view_ref, /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); +} + +TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneClippedView) { + fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher; + fuchsia::ui::views::ViewportCreationToken viewport_creation_token; + fuchsia::ui::views::ViewCreationToken view_creation_token; + fuchsia::ui::views::ViewRef view_ref; + auto view_creation_token_status = zx::channel::create( + 0u, &viewport_creation_token.value, &view_creation_token.value); + ASSERT_EQ(view_creation_token_status, ZX_OK); + auto view_ref_pair = scenic::ViewRefPair::New(); + view_ref_pair.view_ref.Clone(&view_ref); + + // Create the `FlatlandExternalViewEmbedder` and pump the message loop until + // the initial scene graph is setup. + FlatlandExternalViewEmbedder external_view_embedder( + std::move(view_creation_token), + fuchsia::ui::views::ViewIdentityOnCreation{ + .view_ref = std::move(view_ref_pair.view_ref), + .view_ref_control = std::move(view_ref_pair.control_ref), + }, + fuchsia::ui::composition::ViewBoundProtocols{}, + parent_viewport_watcher.NewRequest(), flatland_connection(), + fake_surface_producer()); + flatland_connection()->Present(); + loop().RunUntilIdle(); + fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u)); + loop().RunUntilIdle(); + EXPECT_THAT(fake_flatland().graph(), + IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, + view_ref)); + + // Create the view before drawing the scene. + const SkSize child_view_size_signed = SkSize::Make(256.f, 512.f); + const fuchsia::math::SizeU child_view_size{ + static_cast(child_view_size_signed.width()), + static_cast(child_view_size_signed.height())}; + auto [child_view_token, child_viewport_token] = ViewTokenPair::New(); + const uint32_t child_view_id = child_viewport_token.value.get(); + + const int kOpacity = 200; + const float kOpacityFloat = 200 / 255.0f; + const fuchsia::math::VecF kScale{3.0f, 4.0f}; + const int kTranslateX = 10; + const int kTranslateY = 20; + + auto matrix = SkMatrix::I(); + matrix.setScaleX(kScale.x); + matrix.setScaleY(kScale.y); + matrix.setTranslateX(kTranslateX); + matrix.setTranslateY(kTranslateY); + + SkRect kClipRect = + SkRect::MakeXYWH(30, 40, child_view_size_signed.width() - 50, + child_view_size_signed.height() - 60); + fuchsia::math::Rect kClipInMathRect = { + static_cast(kClipRect.x()), static_cast(kClipRect.y()), + static_cast(kClipRect.width()), + static_cast(kClipRect.height())}; + + auto mutators_stack = flutter::MutatorsStack(); + mutators_stack.PushOpacity(kOpacity); + mutators_stack.PushTransform(matrix); + mutators_stack.PushClipRect(kClipRect); + + flutter::EmbeddedViewParams child_view_params(matrix, child_view_size_signed, + mutators_stack); + external_view_embedder.CreateView( + child_view_id, []() {}, + [](fuchsia::ui::composition::ContentId, + fuchsia::ui::composition::ChildViewWatcherHandle) {}); + const SkRect child_view_occlusion_hint = SkRect::MakeLTRB(1, 2, 3, 4); + const fuchsia::math::Inset child_view_inset{ + static_cast(child_view_occlusion_hint.top()), + static_cast(child_view_occlusion_hint.right()), + static_cast(child_view_occlusion_hint.bottom()), + static_cast(child_view_occlusion_hint.left())}; + external_view_embedder.SetViewProperties( + child_view_id, child_view_occlusion_hint, /*hit_testable=*/false, + /*focusable=*/false); + + // We must take into account the effect of DPR on the view scale. + const float kDPR = 2.0f; + const float kInvDPR = 1.f / kDPR; + + // Draw the scene. The scene graph shouldn't change yet. + const SkISize frame_size_signed = SkISize::Make(512, 512); + const fuchsia::math::SizeU frame_size{ + static_cast(frame_size_signed.width()), + static_cast(frame_size_signed.height())}; + DrawFrameWithView( + external_view_embedder, frame_size_signed, kDPR, child_view_id, + child_view_params, + [](SkCanvas* canvas) { + const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(), + canvas->imageInfo().height()); + SkPaint rect_paint; + rect_paint.setColor(SK_ColorGREEN); + canvas->translate(canvas_size.width() / 4.f, + canvas_size.height() / 2.f); + canvas->drawRect(SkRect::MakeWH(canvas_size.width() / 32.f, + canvas_size.height() / 32.f), + rect_paint); + }, + [](SkCanvas* canvas) { + const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(), + canvas->imageInfo().height()); + SkPaint rect_paint; + rect_paint.setColor(SK_ColorRED); + canvas->translate(canvas_size.width() * 3.f / 4.f, + canvas_size.height() / 2.f); + canvas->drawRect(SkRect::MakeWH(canvas_size.width() / 32.f, + canvas_size.height() / 32.f), + rect_paint); + }); + EXPECT_THAT(fake_flatland().graph(), + IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, + view_ref)); + + // Pump the message loop. The scene updates should propagate to flatland. + loop().RunUntilIdle(); + fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u)); + loop().RunUntilIdle(); + + EXPECT_THAT( + fake_flatland().graph(), + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)}), + IsClipTransformLayer( + {kTranslateX, kTranslateY}, kScale, kClipInMathRect, + IsViewportLayer(child_view_token, child_view_size, + child_view_inset, {0, 0}, + FakeTransform::kDefaultScale, kOpacityFloat)), + IsImageLayer( + frame_size, kUpperLayerBlendMode, + {IsHitRegion( + /* x */ 384.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}, + {kInvDPR, kInvDPR})); + + // Draw another frame with view, but get rid of the clips this time. This + // should remove all ClipTransformLayer instances. + auto new_matrix = SkMatrix::I(); + new_matrix.setScaleX(kScale.x); + new_matrix.setScaleY(kScale.y); + auto new_mutators_stack = flutter::MutatorsStack(); + new_mutators_stack.PushOpacity(kOpacity); + new_mutators_stack.PushTransform(new_matrix); + flutter::EmbeddedViewParams new_child_view_params( + new_matrix, child_view_size_signed, new_mutators_stack); + DrawFrameWithView( + external_view_embedder, frame_size_signed, kDPR, child_view_id, + new_child_view_params, + [](SkCanvas* canvas) { + const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(), + canvas->imageInfo().height()); + SkPaint rect_paint; + rect_paint.setColor(SK_ColorGREEN); + canvas->translate(canvas_size.width() / 4.f, + canvas_size.height() / 2.f); + canvas->drawRect(SkRect::MakeWH(canvas_size.width() / 32.f, + canvas_size.height() / 32.f), + rect_paint); + }, + [](SkCanvas* canvas) { + const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(), + canvas->imageInfo().height()); + SkPaint rect_paint; + rect_paint.setColor(SK_ColorRED); + canvas->translate(canvas_size.width() * 3.f / 4.f, + canvas_size.height() / 2.f); + canvas->drawRect(SkRect::MakeWH(canvas_size.width() / 32.f, + canvas_size.height() / 32.f), + rect_paint); + }); + loop().RunUntilIdle(); + fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u)); + loop().RunUntilIdle(); + EXPECT_THAT( + fake_flatland().graph(), + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)}), + IsViewportLayer(child_view_token, child_view_size, child_view_inset, + {0, 0}, kScale, kOpacityFloat), + IsImageLayer( + frame_size, kUpperLayerBlendMode, + {IsHitRegion( + /* x */ 384.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}, + {kInvDPR, kInvDPR})); + + // Destroy the view and draw another frame without the view. + external_view_embedder.DestroyView( + child_view_id, [](fuchsia::ui::composition::ContentId) {}); + DrawSimpleFrame( + external_view_embedder, frame_size_signed, 1.f, [](SkCanvas* canvas) { + const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(), + canvas->imageInfo().height()); + SkPaint rect_paint; + rect_paint.setColor(SK_ColorGREEN); + canvas->translate(canvas_size.width() / 4.f, + canvas_size.height() / 2.f); + canvas->drawRect(SkRect::MakeWH(canvas_size.width() / 32.f, + canvas_size.height() / 32.f), + rect_paint); + }); + loop().RunUntilIdle(); + EXPECT_THAT( + fake_flatland().graph(), + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); } TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView_NoOverlay) { @@ -736,24 +1071,40 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView_NoOverlay) { loop().RunUntilIdle(); EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, - view_ref, /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), - IsViewportLayer(child_view_token, child_view_size, - FakeViewport::kDefaultViewportInset, - {0, 0}, kScale, kOpacityFloat)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)}), + IsViewportLayer(child_view_token, child_view_size, + FakeViewport::kDefaultViewportInset, {0, 0}, kScale, + kOpacityFloat)})); // Destroy the view. The scene graph shouldn't change yet. external_view_embedder.DestroyView( child_view_id, [](fuchsia::ui::composition::ContentId) {}); EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, - view_ref, /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), - IsViewportLayer(child_view_token, child_view_size, - FakeViewport::kDefaultViewportInset, - {0, 0}, kScale, kOpacityFloat)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)}), + IsViewportLayer(child_view_token, child_view_size, + FakeViewport::kDefaultViewportInset, {0, 0}, kScale, + kOpacityFloat)})); // Draw another frame without the view. The scene graph shouldn't change yet. DrawSimpleFrame( @@ -771,20 +1122,36 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView_NoOverlay) { EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, - view_ref, /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), - IsViewportLayer(child_view_token, child_view_size, - FakeViewport::kDefaultViewportInset, - {0, 0}, kScale, kOpacityFloat)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)}), + IsViewportLayer(child_view_token, child_view_size, + FakeViewport::kDefaultViewportInset, {0, 0}, kScale, + kOpacityFloat)})); // Pump the message loop. The scene updates should propagate to flatland. loop().RunUntilIdle(); EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, - view_ref, /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); } TEST_F(FlatlandExternalViewEmbedderTest, @@ -850,18 +1217,36 @@ TEST_F(FlatlandExternalViewEmbedderTest, loop().RunUntilIdle(); EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref, - /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, + /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); // Destroy the view. The scene graph shouldn't change yet. external_view_embedder.DestroyView( child_view_id, [](fuchsia::ui::composition::ContentId) {}); EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref, - /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, + /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); // Draw another frame without the view and change the size. The scene graph // shouldn't change yet. @@ -883,17 +1268,208 @@ TEST_F(FlatlandExternalViewEmbedderTest, }); EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref, - /*layers*/ - {IsImageLayer(frame_size, kFirstLayerBlendMode, 1)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, + /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); // Pump the message loop. The scene updates should propagate to flatland. loop().RunUntilIdle(); EXPECT_THAT( fake_flatland().graph(), - IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, - view_ref, /*layers*/ - {IsImageLayer(new_frame_size, kFirstLayerBlendMode, 1)})); + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ + {IsImageLayer( + new_frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 64.f, + /* y */ 128.f, + /* width */ 8.f, + /* height */ 8.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); +} + +// This test case exercises the scenario in which the view contains two disjoint +// regions with painted content; we should generate two separate hit regions +// matching the bounds of the painted regions in this case. +TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene_DisjointHitRegions) { + fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher; + fuchsia::ui::views::ViewportCreationToken viewport_creation_token; + fuchsia::ui::views::ViewCreationToken view_creation_token; + fuchsia::ui::views::ViewRef view_ref; + auto view_creation_token_status = zx::channel::create( + 0u, &viewport_creation_token.value, &view_creation_token.value); + ASSERT_EQ(view_creation_token_status, ZX_OK); + auto view_ref_pair = scenic::ViewRefPair::New(); + view_ref_pair.view_ref.Clone(&view_ref); + + // Create the `FlatlandExternalViewEmbedder` and pump the message loop until + // the initial scene graph is setup. + FlatlandExternalViewEmbedder external_view_embedder( + std::move(view_creation_token), + fuchsia::ui::views::ViewIdentityOnCreation{ + .view_ref = std::move(view_ref_pair.view_ref), + .view_ref_control = std::move(view_ref_pair.control_ref), + }, + fuchsia::ui::composition::ViewBoundProtocols{}, + parent_viewport_watcher.NewRequest(), flatland_connection(), + fake_surface_producer()); + flatland_connection()->Present(); + loop().RunUntilIdle(); + fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u)); + loop().RunUntilIdle(); + EXPECT_THAT(fake_flatland().graph(), + IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, + view_ref)); + + // Draw the scene. The scene graph shouldn't change yet. + const SkISize frame_size_signed = SkISize::Make(512, 512); + const fuchsia::math::SizeU frame_size{ + static_cast(frame_size_signed.width()), + static_cast(frame_size_signed.height())}; + DrawSimpleFrame( + external_view_embedder, frame_size_signed, 1.f, [](SkCanvas* canvas) { + const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(), + canvas->imageInfo().height()); + + SkRect paint_region_1, paint_region_2; + + paint_region_1 = SkRect::MakeXYWH( + canvas_size.width() / 4.f, canvas_size.height() / 2.f, + canvas_size.width() / 32.f, canvas_size.height() / 32.f); + + SkPaint rect_paint; + rect_paint.setColor(SK_ColorGREEN); + canvas->drawRect(paint_region_1, rect_paint); + + paint_region_2 = SkRect::MakeXYWH( + canvas_size.width() * 3.f / 4.f, canvas_size.height() / 2.f, + canvas_size.width() / 32.f, canvas_size.height() / 32.f); + + rect_paint.setColor(SK_ColorRED); + canvas->drawRect(paint_region_2, rect_paint); + }); + EXPECT_THAT(fake_flatland().graph(), + IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, + view_ref)); + + // Pump the message loop. The scene updates should propagate to flatland. + loop().RunUntilIdle(); + + EXPECT_THAT( + fake_flatland().graph(), + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, + /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT), + IsHitRegion( + /* x */ 384.f, + /* y */ 256.f, + /* width */ 16.f, + /* height */ 16.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); +} + +// This test case exercises the scenario in which the view contains two +// overlapping regions with painted content; we should generate one hit +// region matching the union of the bounds of the two painted regions in +// this case. +TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene_OverlappingHitRegions) { + fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher; + fuchsia::ui::views::ViewportCreationToken viewport_creation_token; + fuchsia::ui::views::ViewCreationToken view_creation_token; + fuchsia::ui::views::ViewRef view_ref; + auto view_creation_token_status = zx::channel::create( + 0u, &viewport_creation_token.value, &view_creation_token.value); + ASSERT_EQ(view_creation_token_status, ZX_OK); + auto view_ref_pair = scenic::ViewRefPair::New(); + view_ref_pair.view_ref.Clone(&view_ref); + + // Create the `FlatlandExternalViewEmbedder` and pump the message loop until + // the initial scene graph is setup. + FlatlandExternalViewEmbedder external_view_embedder( + std::move(view_creation_token), + fuchsia::ui::views::ViewIdentityOnCreation{ + .view_ref = std::move(view_ref_pair.view_ref), + .view_ref_control = std::move(view_ref_pair.control_ref), + }, + fuchsia::ui::composition::ViewBoundProtocols{}, + parent_viewport_watcher.NewRequest(), flatland_connection(), + fake_surface_producer()); + flatland_connection()->Present(); + loop().RunUntilIdle(); + fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u)); + loop().RunUntilIdle(); + EXPECT_THAT(fake_flatland().graph(), + IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, + view_ref)); + + // Draw the scene. The scene graph shouldn't change yet. + const SkISize frame_size_signed = SkISize::Make(512, 512); + const fuchsia::math::SizeU frame_size{ + static_cast(frame_size_signed.width()), + static_cast(frame_size_signed.height())}; + DrawSimpleFrame( + external_view_embedder, frame_size_signed, 1.f, [](SkCanvas* canvas) { + const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(), + canvas->imageInfo().height()); + + SkRect paint_region_1, paint_region_2; + + paint_region_1 = SkRect::MakeXYWH( + canvas_size.width() / 4.f, canvas_size.height() / 2.f, + 3.f * canvas_size.width() / 8.f, canvas_size.height() / 4.f); + + SkPaint rect_paint; + rect_paint.setColor(SK_ColorGREEN); + canvas->drawRect(paint_region_1, rect_paint); + + paint_region_2 = SkRect::MakeXYWH( + canvas_size.width() * 3.f / 8.f, canvas_size.height() / 2.f, + 3.f * canvas_size.width() / 8.f, canvas_size.height() / 4.f); + + rect_paint.setColor(SK_ColorRED); + canvas->drawRect(paint_region_2, rect_paint); + }); + EXPECT_THAT(fake_flatland().graph(), + IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, + view_ref)); + + // Pump the message loop. The scene updates should propagate to flatland. + loop().RunUntilIdle(); + + EXPECT_THAT( + fake_flatland().graph(), + IsFlutterGraph( + parent_viewport_watcher, viewport_creation_token, view_ref, + /*layers*/ + {IsImageLayer( + frame_size, kFirstLayerBlendMode, + {IsHitRegion( + /* x */ 128.f, + /* y */ 256.f, + /* width */ 256.f, + /* height */ 128.f, + /* hit_test */ + fuchsia::ui::composition::HitTestInteraction::DEFAULT)})})); } } // namespace flutter_runner::testing diff --git a/shell/platform/fuchsia/flutter/tests/gfx_session_connection_unittests.cc b/shell/platform/fuchsia/flutter/tests/gfx_session_connection_unittests.cc index 9a7e314ca0602..d8fdec58f3a1a 100644 --- a/shell/platform/fuchsia/flutter/tests/gfx_session_connection_unittests.cc +++ b/shell/platform/fuchsia/flutter/tests/gfx_session_connection_unittests.cc @@ -180,14 +180,14 @@ TEST_F(GfxSessionConnectionTest, BasicPresent) { // (`RequestPresentationTimes` or `Present` calls) were handled. size_t request_times_called = 0u; size_t presents_called = 0u; - fake_session().SetRequestPresentationTimesHandler([&request_times_called]( - auto...) -> auto { - request_times_called++; - return FuturePresentationTimes{ - .future_presentations = {}, - .remaining_presents_in_flight_allowed = 1, - }; - }); + fake_session().SetRequestPresentationTimesHandler( + [&request_times_called](auto...) -> auto { + request_times_called++; + return FuturePresentationTimes{ + .future_presentations = {}, + .remaining_presents_in_flight_allowed = 1, + }; + }); fake_session().SetPresent2Handler([&presents_called](auto...) -> auto { presents_called++; return FuturePresentationTimes{ diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 44fa1b36ac490..6c9c91f102a0d 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -868,3 +868,20 @@ static void fl_key_embedder_responder_handle_event( self->send_key_event(&kEmptyEvent, nullptr, nullptr); } } + +void fl_key_embedder_responder_sync_modifiers_if_needed( + FlKeyEmbedderResponder* responder, + guint state, + double event_time) { + const double timestamp = event_time * kMicrosecondsPerMillisecond; + + SyncStateLoopContext sync_state_context; + sync_state_context.self = responder; + sync_state_context.state = state; + sync_state_context.timestamp = timestamp; + + // Update pressing states. + g_hash_table_foreach(responder->modifier_bit_to_checked_keys, + synchronize_pressed_states_loop_body, + &sync_state_context); +} diff --git a/shell/platform/linux/fl_key_embedder_responder.h b/shell/platform/linux/fl_key_embedder_responder.h index 0eb0659435bd5..d7b3af8c0b410 100644 --- a/shell/platform/linux/fl_key_embedder_responder.h +++ b/shell/platform/linux/fl_key_embedder_responder.h @@ -50,6 +50,20 @@ G_DECLARE_FINAL_TYPE(FlKeyEmbedderResponder, FlKeyEmbedderResponder* fl_key_embedder_responder_new( EmbedderSendKeyEvent send_key_event); +/** + * fl_key_embedder_responder_sync_modifiers_if_needed: + * @responder: the #FlKeyEmbedderResponder self. + * @state: the state of the modifiers mask. + * @event_time: the time attribute of the incoming GDK event. + * + * If needed, synthesize modifier keys up and down event by comparing their + * current pressing states with the given modifiers mask. + */ +void fl_key_embedder_responder_sync_modifiers_if_needed( + FlKeyEmbedderResponder* responder, + guint state, + double event_time); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EMBEDDER_RESPONDER_H_ diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 06762cee6294d..fc3c8ca31b38a 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -610,3 +610,14 @@ gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* self) { return self->pending_responds->len == 0 && self->pending_redispatches->len == 0; } + +void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* self, + guint state, + double event_time) { + // The embedder responder is the first element in + // FlKeyboardManager.responder_list. + FlKeyEmbedderResponder* responder = + FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0)); + fl_key_embedder_responder_sync_modifiers_if_needed(responder, state, + event_time); +} diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index fb5d35d9bce52..688e49f972a92 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -70,6 +70,19 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, */ gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* manager); +/** + * fl_keyboard_manager_sync_modifier_if_needed: + * @manager: the #FlKeyboardManager self. + * @state: the state of the modifiers mask. + * @event_time: the time attribute of the incoming GDK event. + * + * If needed, synthesize modifier keys up and down event by comparing their + * current pressing states with the given modifiers mask. + */ +void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* manager, + guint state, + double event_time); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_ diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index b9856cedfe506..b408cb89eac00 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -32,20 +32,28 @@ call_records.clear() namespace { +using ::flutter::testing::keycodes::kLogicalAltLeft; using ::flutter::testing::keycodes::kLogicalBracketLeft; using ::flutter::testing::keycodes::kLogicalComma; +using ::flutter::testing::keycodes::kLogicalControlLeft; using ::flutter::testing::keycodes::kLogicalDigit1; using ::flutter::testing::keycodes::kLogicalKeyA; using ::flutter::testing::keycodes::kLogicalKeyB; using ::flutter::testing::keycodes::kLogicalKeyM; using ::flutter::testing::keycodes::kLogicalKeyQ; +using ::flutter::testing::keycodes::kLogicalMetaLeft; using ::flutter::testing::keycodes::kLogicalMinus; using ::flutter::testing::keycodes::kLogicalParenthesisRight; using ::flutter::testing::keycodes::kLogicalSemicolon; +using ::flutter::testing::keycodes::kLogicalShiftLeft; using ::flutter::testing::keycodes::kLogicalUnderscore; +using ::flutter::testing::keycodes::kPhysicalAltLeft; +using ::flutter::testing::keycodes::kPhysicalControlLeft; using ::flutter::testing::keycodes::kPhysicalKeyA; using ::flutter::testing::keycodes::kPhysicalKeyB; +using ::flutter::testing::keycodes::kPhysicalMetaLeft; +using ::flutter::testing::keycodes::kPhysicalShiftLeft; // Hardware key codes. typedef std::function AsyncKeyCallback; @@ -880,6 +888,44 @@ TEST(FlKeyboardManagerTest, CorrectLogicalKeyForLayouts) { VERIFY_DOWN(kLogicalBracketLeft, "["); } +TEST(FlKeyboardManagerTest, SynthesizeModifiersIfNeeded) { + KeyboardTester tester; + std::vector call_records; + tester.recordEmbedderCallsTo(call_records); + + auto verifyModifierIsSynthesized = [&](GdkModifierType mask, + uint64_t physical, uint64_t logical) { + // Modifier is pressed. + guint state = mask; + fl_keyboard_manager_sync_modifier_if_needed(tester.manager(), state, 1000); + EXPECT_EQ(call_records.size(), 1u); + EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, physical, + logical, NULL, true); + // Modifier is released. + state = state ^ mask; + fl_keyboard_manager_sync_modifier_if_needed(tester.manager(), state, 1001); + EXPECT_EQ(call_records.size(), 2u); + EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeUp, physical, logical, + NULL, true); + call_records.clear(); + }; + + // No modifiers pressed. + guint state = 0; + fl_keyboard_manager_sync_modifier_if_needed(tester.manager(), state, 1000); + EXPECT_EQ(call_records.size(), 0u); + call_records.clear(); + + // Press and release each modifier once. + verifyModifierIsSynthesized(GDK_CONTROL_MASK, kPhysicalControlLeft, + kLogicalControlLeft); + verifyModifierIsSynthesized(GDK_META_MASK, kPhysicalMetaLeft, + kLogicalMetaLeft); + verifyModifierIsSynthesized(GDK_MOD1_MASK, kPhysicalAltLeft, kLogicalAltLeft); + verifyModifierIsSynthesized(GDK_SHIFT_MASK, kPhysicalShiftLeft, + kLogicalShiftLeft); +} + // The following layout data is generated using DEBUG_PRINT_LAYOUT. const MockGroupLayoutData kLayoutUs0{{ diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 967dd67d7cbce..69fea7ccafe6f 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -164,6 +164,8 @@ static gboolean send_pointer_button_event(FlView* self, GdkEventButton* event) { fl_scrolling_manager_set_last_mouse_position(self->scrolling_manager, event->x * scale_factor, event->y * scale_factor); + fl_keyboard_manager_sync_modifier_if_needed(self->keyboard_manager, + event->state, event->time); fl_engine_send_mouse_pointer_event( self->engine, phase, event->time * kMicrosecondsPerMillisecond, event->x * scale_factor, event->y * scale_factor, 0, 0, @@ -172,7 +174,7 @@ static gboolean send_pointer_button_event(FlView* self, GdkEventButton* event) { return TRUE; } -// Geneartes a mouse pointer event if the pointer appears inside the window. +// Generates a mouse pointer event if the pointer appears inside the window. static void check_pointer_inside(FlView* view, GdkEvent* event) { if (!view->pointer_inside) { view->pointer_inside = TRUE; @@ -402,6 +404,9 @@ static gboolean motion_notify_event_cb(GtkWidget* widget, check_pointer_inside(view, reinterpret_cast(event)); gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(view)); + + fl_keyboard_manager_sync_modifier_if_needed(view->keyboard_manager, + event->state, event->time); fl_engine_send_mouse_pointer_event( view->engine, view->button_state != 0 ? kMove : kHover, event->time * kMicrosecondsPerMillisecond, event->x * scale_factor, diff --git a/shell/platform/windows/platform_handler_unittests.cc b/shell/platform/windows/platform_handler_unittests.cc index 02a98281f4295..604ffcb0679eb 100644 --- a/shell/platform/windows/platform_handler_unittests.cc +++ b/shell/platform/windows/platform_handler_unittests.cc @@ -19,36 +19,42 @@ namespace testing { namespace { using ::testing::_; +using ::testing::NiceMock; +using ::testing::Return; static constexpr char kChannelName[] = "flutter/platform"; -static constexpr char kGetClipboardDataMethod[] = "Clipboard.getData"; -static constexpr char kHasStringsClipboardMethod[] = "Clipboard.hasStrings"; -static constexpr char kSetClipboardDataMethod[] = "Clipboard.setData"; -static constexpr char kPlaySoundMethod[] = "SystemSound.play"; +static constexpr char kClipboardGetDataMessage[] = + "{\"method\":\"Clipboard.getData\",\"args\":\"text/plain\"}"; +static constexpr char kClipboardGetDataFakeContentTypeMessage[] = + "{\"method\":\"Clipboard.getData\",\"args\":\"text/madeupcontenttype\"}"; +static constexpr char kClipboardHasStringsMessage[] = + "{\"method\":\"Clipboard.hasStrings\",\"args\":\"text/plain\"}"; +static constexpr char kClipboardHasStringsFakeContentTypeMessage[] = + "{\"method\":\"Clipboard.hasStrings\",\"args\":\"text/madeupcontenttype\"}"; +static constexpr char kClipboardSetDataMessage[] = + "{\"method\":\"Clipboard.setData\",\"args\":{\"text\":\"hello\"}}"; +static constexpr char kClipboardSetDataUnknownTypeMessage[] = + "{\"method\":\"Clipboard.setData\",\"args\":{\"madeuptype\":\"hello\"}}"; +static constexpr char kSystemSoundTypeAlertMessage[] = + "{\"method\":\"SystemSound.play\",\"args\":\"SystemSoundType.alert\"}"; -static constexpr char kTextPlainFormat[] = "text/plain"; -static constexpr char kFakeContentType[] = "text/madeupcontenttype"; - -static constexpr char kSoundTypeAlert[] = "SystemSoundType.alert"; - -static constexpr char kValueKey[] = "value"; static constexpr int kAccessDeniedErrorCode = 5; static constexpr int kErrorSuccess = 0; static constexpr int kArbitraryErrorCode = 1; // Test implementation of PlatformHandler to allow testing the PlatformHandler // logic. -class TestPlatformHandler : public PlatformHandler { +class MockPlatformHandler : public PlatformHandler { public: - explicit TestPlatformHandler( + explicit MockPlatformHandler( BinaryMessenger* messenger, FlutterWindowsView* view, std::optional()>> scoped_clipboard_provider = std::nullopt) : PlatformHandler(messenger, view, scoped_clipboard_provider) {} - virtual ~TestPlatformHandler() = default; + virtual ~MockPlatformHandler() = default; MOCK_METHOD2(GetPlainText, void(std::unique_ptr>, @@ -63,461 +69,315 @@ class TestPlatformHandler : public PlatformHandler { std::unique_ptr>)); }; -// Mock result to inspect results of PlatformHandler calls. -class MockMethodResult : public MethodResult { +// A test version of the private ScopedClipboard. +class MockScopedClipboard : public ScopedClipboardInterface { public: - MOCK_METHOD1(SuccessInternal, void(const rapidjson::Document*)); - MOCK_METHOD3(ErrorInternal, - void(const std::string&, - const std::string&, - const rapidjson::Document*)); - MOCK_METHOD0(NotImplementedInternal, void()); + MOCK_METHOD(int, Open, (HWND window), (override)); + MOCK_METHOD(bool, HasString, (), (override)); + MOCK_METHOD((std::variant), GetString, (), (override)); + MOCK_METHOD(int, SetString, (const std::wstring string), (override)); }; -// A test version of system clipboard. -class MockSystemClipboard { - public: - void OpenClipboard() { opened = true; } - void CloseClipboard() { opened = false; } - bool opened = false; -}; +std::string SimulatePlatformMessage(TestBinaryMessenger* messenger, + std::string message) { + std::string result; + EXPECT_TRUE(messenger->SimulateEngineMessage( + kChannelName, reinterpret_cast(message.c_str()), + message.size(), + [result = &result](const uint8_t* reply, size_t reply_size) { + std::string response(reinterpret_cast(reply), reply_size); -// A test version of the private ScopedClipboard. -class TestScopedClipboard : public ScopedClipboardInterface { - public: - TestScopedClipboard(int open_error, - bool has_strings, - std::shared_ptr clipboard); - ~TestScopedClipboard(); + *result = response; + })); - // Prevent copying. - TestScopedClipboard(TestScopedClipboard const&) = delete; - TestScopedClipboard& operator=(TestScopedClipboard const&) = delete; + return result; +} - int Open(HWND window) override; +} // namespace - bool HasString() override; +TEST(PlatformHandler, GetClipboardData) { + TestBinaryMessenger messenger; + FlutterWindowsView view( + std::make_unique>()); - std::variant GetString() override; + PlatformHandler platform_handler(&messenger, &view, []() { + auto clipboard = std::make_unique(); - int SetString(const std::wstring string) override; + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kErrorSuccess)); + EXPECT_CALL(*clipboard.get(), HasString).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*clipboard.get(), GetString) + .Times(1) + .WillOnce(Return(std::wstring(L"Hello world"))); - private: - bool opened_ = false; - bool has_strings_; - int open_error_; - std::shared_ptr clipboard_; -}; + return clipboard; + }); -TestScopedClipboard::TestScopedClipboard( - int open_error, - bool has_strings, - std::shared_ptr clipboard = nullptr) { - open_error_ = open_error; - has_strings_ = has_strings; - clipboard_ = clipboard; -} + std::string result = + SimulatePlatformMessage(&messenger, kClipboardGetDataMessage); -TestScopedClipboard::~TestScopedClipboard() { - if ((!open_error_) && clipboard_ != nullptr) { - clipboard_->CloseClipboard(); - } + EXPECT_EQ(result, "[{\"text\":\"Hello world\"}]"); } -int TestScopedClipboard::Open(HWND window) { - if ((!open_error_) && clipboard_ != nullptr) { - clipboard_->OpenClipboard(); - } - return open_error_; -} +TEST(PlatformHandler, GetClipboardDataRejectsUnknownContentType) { + TestBinaryMessenger messenger; + FlutterWindowsView view( + std::make_unique>()); + PlatformHandler platform_handler(&messenger, &view); -bool TestScopedClipboard::HasString() { - return has_strings_; -} + // Requesting an unknown content type is an error. + std::string result = SimulatePlatformMessage( + &messenger, kClipboardGetDataFakeContentTypeMessage); -std::variant TestScopedClipboard::GetString() { - return -1; + EXPECT_EQ(result, "[\"Clipboard error\",\"Unknown clipboard format\",null]"); } -int TestScopedClipboard::SetString(const std::wstring string) { - return -1; -} - -} // namespace - -TEST(PlatformHandler, GettingTextCallsThrough) { +TEST(PlatformHandler, GetClipboardDataReportsOpenFailure) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - auto system_clipboard = std::make_shared(); - TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); + std::make_unique>()); + + PlatformHandler platform_handler(&messenger, &view, []() { + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kArbitraryErrorCode)); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kTextPlainFormat); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kGetClipboardDataMethod, - std::move(args))); - - // Set up a handler to call a response on |result| so that it doesn't log - // on destruction about leaking. - ON_CALL(platform_handler, GetPlainText) - .WillByDefault( - [](std::unique_ptr> result, - auto key) { result->NotImplemented(); }); - - EXPECT_CALL(platform_handler, GetPlainText(_, ::testing::StrEq("text"))); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [](const uint8_t* reply, size_t reply_size) {})); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardGetDataMessage); + + EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to open clipboard\",1]"); } -TEST(PlatformHandler, RejectsGettingUnknownTypes) { +TEST(PlatformHandler, GetClipboardDataReportsGetDataFailure) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - auto system_clipboard = std::make_shared(); - TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); + std::make_unique>()); + + PlatformHandler platform_handler(&messenger, &view, []() { + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kErrorSuccess)); + EXPECT_CALL(*clipboard.get(), HasString).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*clipboard.get(), GetString) + .Times(1) + .WillOnce(Return(kArbitraryErrorCode)); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kFakeContentType); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kGetClipboardDataMethod, - std::move(args))); - - MockMethodResult result; - // Requsting an unknow content type is an error. - EXPECT_CALL(result, ErrorInternal(_, _, _)); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [&](const uint8_t* reply, size_t reply_size) { - JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( - reply, reply_size, &result); - })); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardGetDataMessage); + + EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to get clipboard data\",1]"); } -TEST(PlatformHandler, GetHasStringsCallsThrough) { +TEST(PlatformHandler, ClipboardHasStrings) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - auto system_clipboard = std::make_shared(); - TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); + std::make_unique>()); + + PlatformHandler platform_handler(&messenger, &view, []() { + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kErrorSuccess)); + EXPECT_CALL(*clipboard.get(), HasString).Times(1).WillOnce(Return(true)); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kTextPlainFormat); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kHasStringsClipboardMethod, - std::move(args))); - - // Set up a handler to call a response on |result| so that it doesn't log - // on destruction about leaking. - ON_CALL(platform_handler, GetHasStrings) - .WillByDefault( - [](std::unique_ptr> result) { - result->NotImplemented(); - }); - - EXPECT_CALL(platform_handler, GetHasStrings(_)); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [](const uint8_t* reply, size_t reply_size) {})); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardHasStringsMessage); + + EXPECT_EQ(result, "[{\"value\":true}]"); } -TEST(PlatformHandler, RejectsGetHasStringsOnUnknownTypes) { +TEST(PlatformHandler, ClipboardHasStringsReturnsFalse) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - auto system_clipboard = std::make_shared(); - TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); + std::make_unique>()); + + PlatformHandler platform_handler(&messenger, &view, []() { + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kErrorSuccess)); + EXPECT_CALL(*clipboard.get(), HasString).Times(1).WillOnce(Return(false)); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kFakeContentType); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kHasStringsClipboardMethod, - std::move(args))); - - MockMethodResult result; - // Requsting an unknow content type is an error. - EXPECT_CALL(result, ErrorInternal(_, _, _)); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [&](const uint8_t* reply, size_t reply_size) { - JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( - reply, reply_size, &result); - })); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardHasStringsMessage); + + EXPECT_EQ(result, "[{\"value\":false}]"); } -TEST(PlatformHandler, SettingTextCallsThrough) { +TEST(PlatformHandler, ClipboardHasStringsRejectsUnknownContentType) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - auto system_clipboard = std::make_shared(); - TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); - }); + std::make_unique>()); + PlatformHandler platform_handler(&messenger, &view); + + std::string result = SimulatePlatformMessage( + &messenger, kClipboardHasStringsFakeContentTypeMessage); - auto args = std::make_unique(rapidjson::kObjectType); - auto& allocator = args->GetAllocator(); - args->AddMember("text", "hello", allocator); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kSetClipboardDataMethod, - std::move(args))); - - // Set up a handler to call a response on |result| so that it doesn't log - // on destruction about leaking. - ON_CALL(platform_handler, SetPlainText) - .WillByDefault( - [](auto value, - std::unique_ptr> result) { - result->NotImplemented(); - }); - - EXPECT_CALL(platform_handler, SetPlainText(::testing::StrEq("hello"), _)); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [](const uint8_t* reply, size_t reply_size) {})); + EXPECT_EQ(result, "[\"Clipboard error\",\"Unknown clipboard format\",null]"); } -TEST(PlatformHandler, RejectsSettingUnknownTypes) { +// Regression test for https://github.com/flutter/flutter/issues/95817. +TEST(PlatformHandler, ClipboardHasStringsIgnoresPermissionErrors) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - auto system_clipboard = std::make_shared(); - TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); + std::make_unique>()); + + PlatformHandler platform_handler(&messenger, &view, []() { + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kAccessDeniedErrorCode)); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kObjectType); - auto& allocator = args->GetAllocator(); - args->AddMember("madeuptype", "hello", allocator); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kSetClipboardDataMethod, - std::move(args))); - - MockMethodResult result; - // Requsting an unknow content type is an error. - EXPECT_CALL(result, ErrorInternal(_, _, _)); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [&](const uint8_t* reply, size_t reply_size) { - JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( - reply, reply_size, &result); - })); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardHasStringsMessage); + + EXPECT_EQ(result, "[{\"value\":false}]"); } -TEST(PlatformHandler, PlayingSystemSoundCallsThrough) { +TEST(PlatformHandler, ClipboardHasStringsReportsErrors) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - auto system_clipboard = std::make_shared(); - TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); + std::make_unique>()); + + PlatformHandler platform_handler(&messenger, &view, []() { + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kArbitraryErrorCode)); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kSoundTypeAlert); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kPlaySoundMethod, std::move(args))); - - // Set up a handler to call a response on |result| so that it doesn't log - // on destruction about leaking. - ON_CALL(platform_handler, SystemSoundPlay) - .WillByDefault( - [](auto sound_type, - std::unique_ptr> result) { - result->NotImplemented(); - }); - - EXPECT_CALL(platform_handler, - SystemSoundPlay(::testing::StrEq(kSoundTypeAlert), _)); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [](const uint8_t* reply, size_t reply_size) {})); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardHasStringsMessage); + + EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to open clipboard\",1]"); } -// Regression test for https://github.com/flutter/flutter/issues/95817. -TEST(PlatformHandler, HasStringsAccessDeniedReturnsFalseWithoutError) { +TEST(PlatformHandler, ClipboardSetData) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - // HasStrings will receive access denied on the clipboard, but will return - // false without error. + std::make_unique>()); + PlatformHandler platform_handler(&messenger, &view, []() { - return std::make_unique(kAccessDeniedErrorCode, true); + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kErrorSuccess)); + EXPECT_CALL(*clipboard.get(), SetString) + .Times(1) + .WillOnce([](std::wstring string) { + EXPECT_EQ(string, L"hello"); + return kErrorSuccess; + }); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kTextPlainFormat); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kHasStringsClipboardMethod, - std::move(args))); - - MockMethodResult result; - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& document_allocator = - document.GetAllocator(); - document.AddMember(rapidjson::Value(kValueKey, document_allocator), - rapidjson::Value(false), document_allocator); - - EXPECT_CALL(result, SuccessInternal(_)) - .WillOnce([](const rapidjson::Document* document) { - ASSERT_FALSE((*document)[kValueKey].GetBool()); - }); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [&](const uint8_t* reply, size_t reply_size) { - JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( - reply, reply_size, &result); - })); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardSetDataMessage); + + EXPECT_EQ(result, "[null]"); } -TEST(PlatformHandler, HasStringsSuccessWithStrings) { +TEST(PlatformHandler, ClipboardSetDataUnknownType) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - // HasStrings will succeed and return true. - PlatformHandler platform_handler(&messenger, &view, []() { - return std::make_unique(kErrorSuccess, true); - }); + std::make_unique>()); + PlatformHandler platform_handler(&messenger, &view); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kTextPlainFormat); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kHasStringsClipboardMethod, - std::move(args))); - - MockMethodResult result; - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& document_allocator = - document.GetAllocator(); - document.AddMember(rapidjson::Value(kValueKey, document_allocator), - rapidjson::Value(false), document_allocator); - - EXPECT_CALL(result, SuccessInternal(_)) - .WillOnce([](const rapidjson::Document* document) { - ASSERT_TRUE((*document)[kValueKey].GetBool()); - }); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [&](const uint8_t* reply, size_t reply_size) { - JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( - reply, reply_size, &result); - })); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardSetDataUnknownTypeMessage); + + EXPECT_EQ(result, "[\"Clipboard error\",\"Unknown clipboard format\",null]"); } -TEST(PlatformHandler, HasStringsSuccessWithoutStrings) { +TEST(PlatformHandler, ClipboardSetDataReportsOpenFailure) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - // HasStrings will succeed and return false. + std::make_unique>()); + PlatformHandler platform_handler(&messenger, &view, []() { - return std::make_unique(kErrorSuccess, false); + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kArbitraryErrorCode)); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kTextPlainFormat); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kHasStringsClipboardMethod, - std::move(args))); - - MockMethodResult result; - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& document_allocator = - document.GetAllocator(); - document.AddMember(rapidjson::Value(kValueKey, document_allocator), - rapidjson::Value(false), document_allocator); - - EXPECT_CALL(result, SuccessInternal(_)) - .WillOnce([](const rapidjson::Document* document) { - ASSERT_FALSE((*document)[kValueKey].GetBool()); - }); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [&](const uint8_t* reply, size_t reply_size) { - JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( - reply, reply_size, &result); - })); + std::string result = + SimulatePlatformMessage(&messenger, kClipboardSetDataMessage); + + EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to open clipboard\",1]"); } -TEST(PlatformHandler, HasStringsError) { +TEST(PlatformHandler, ClipboardSetDataReportsSetDataFailure) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - // HasStrings will fail. + std::make_unique>()); + PlatformHandler platform_handler(&messenger, &view, []() { - return std::make_unique(kArbitraryErrorCode, true); + auto clipboard = std::make_unique(); + + EXPECT_CALL(*clipboard.get(), Open) + .Times(1) + .WillOnce(Return(kErrorSuccess)); + EXPECT_CALL(*clipboard.get(), SetString) + .Times(1) + .WillOnce(Return(kArbitraryErrorCode)); + + return clipboard; }); - auto args = std::make_unique(rapidjson::kStringType); - auto& allocator = args->GetAllocator(); - args->SetString(kTextPlainFormat); - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( - MethodCall(kHasStringsClipboardMethod, - std::move(args))); - - MockMethodResult result; - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& document_allocator = - document.GetAllocator(); - document.AddMember(rapidjson::Value(kValueKey, document_allocator), - rapidjson::Value(false), document_allocator); - - EXPECT_CALL(result, SuccessInternal(_)).Times(0); - EXPECT_CALL(result, ErrorInternal(_, _, _)).Times(1); - EXPECT_TRUE(messenger.SimulateEngineMessage( - kChannelName, encoded->data(), encoded->size(), - [&](const uint8_t* reply, size_t reply_size) { - JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( - reply, reply_size, &result); - })); -} + std::string result = + SimulatePlatformMessage(&messenger, kClipboardSetDataMessage); -// Regression test for https://github.com/flutter/flutter/issues/103205. -TEST(PlatformHandler, ReleaseClipboard) { - auto system_clipboard = std::make_shared(); + EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to set clipboard data\",1]"); +} +TEST(PlatformHandler, PlaySystemSound) { TestBinaryMessenger messenger; FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); - }); + std::make_unique>()); + MockPlatformHandler platform_handler(&messenger, &view); - platform_handler.GetPlainText(std::make_unique(), "text"); - ASSERT_FALSE(system_clipboard->opened); + EXPECT_CALL(platform_handler, SystemSoundPlay("SystemSoundType.alert", _)) + .WillOnce([](const std::string& sound, + std::unique_ptr> result) { + result->Success(); + }); - platform_handler.GetHasStrings(std::make_unique()); - ASSERT_FALSE(system_clipboard->opened); + std::string result = + SimulatePlatformMessage(&messenger, kSystemSoundTypeAlertMessage); - platform_handler.SetPlainText("", std::make_unique()); - ASSERT_FALSE(system_clipboard->opened); + EXPECT_EQ(result, "[null]"); } } // namespace testing diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index a665718e4c724..edb758ef99d0d 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -9531,6 +9531,7 @@ engine gpu tonic txt +web_unicode Copyright 2013 The Flutter Authors. All rights reserved. @@ -15647,6 +15648,55 @@ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -------------------------------------------------------------------------------- +web_unicode + +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +See Terms of Use +for definitions of Unicode Inc.’s Data Files and Software. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2022 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in https://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 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 THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. +-------------------------------------------------------------------------------- icu Unicode® Copyright and Terms of Use diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart index eca105ec9d394..9fd025ab04085 100644 --- a/testing/dart/fragment_shader_test.dart +++ b/testing/dart/fragment_shader_test.dart @@ -46,18 +46,15 @@ void main() async { 'blue_green_sampler.frag.iplr', ); final Image blueGreenImage = await _createBlueGreenImage(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); final FragmentShader fragmentShader = program.fragmentShader(); try { - fragmentShader.setSampler(1, imageShader); + fragmentShader.setImageSampler(1, blueGreenImage); fail('Unreachable'); } catch (e) { expect(e, contains('Sampler index out of bounds')); } finally { fragmentShader.dispose(); - imageShader.dispose(); blueGreenImage.dispose(); } }); @@ -86,11 +83,9 @@ void main() async { 'blue_green_sampler.frag.iplr', ); final Image blueGreenImage = await _createBlueGreenImage(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); final FragmentShader shader = program.fragmentShader() - ..setSampler(0, imageShader); + ..setImageSampler(0, blueGreenImage); shader.dispose(); try { final Paint paint = Paint()..shader = shader; // ignore: unused_local_variable @@ -100,7 +95,6 @@ void main() async { } catch (e) { expect(e.toString(), contains('Attempted to set a disposed shader')); } - imageShader.dispose(); blueGreenImage.dispose(); }); @@ -128,19 +122,17 @@ void main() async { } }); - test('Disposed FragmentShader setSampler', () async { + test('Disposed FragmentShader setImageSampler', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'blue_green_sampler.frag.iplr', ); final Image blueGreenImage = await _createBlueGreenImage(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); final FragmentShader shader = program.fragmentShader() - ..setSampler(0, imageShader); + ..setImageSampler(0, blueGreenImage); shader.dispose(); try { - shader.setSampler(0, imageShader); + shader.setImageSampler(0, blueGreenImage); if (assertsEnabled) { fail('Unreachable'); } @@ -155,7 +147,6 @@ void main() async { contains('the native peer has been collected'), ); } - imageShader.dispose(); blueGreenImage.dispose(); }); @@ -209,13 +200,10 @@ void main() async { 'blue_green_sampler.frag.iplr', ); final Image blueGreenImage = await _createBlueGreenImage(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); final FragmentShader shader = program.fragmentShader() - ..setSampler(0, imageShader); + ..setImageSampler(0, blueGreenImage); await _expectShaderRendersGreen(shader); shader.dispose(); - imageShader.dispose(); blueGreenImage.dispose(); }); @@ -224,13 +212,10 @@ void main() async { 'blue_green_sampler.frag.iplr', ); final Image blueGreenImage = _createBlueGreenImageSync(); - final ImageShader imageShader = ImageShader( - blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); final FragmentShader shader = program.fragmentShader() - ..setSampler(0, imageShader); + ..setImageSampler(0, blueGreenImage); await _expectShaderRendersGreen(shader); shader.dispose(); - imageShader.dispose(); blueGreenImage.dispose(); }); @@ -499,11 +484,3 @@ Image _createBlueGreenImageSync() { picture.dispose(); } } - - -final Float64List _identityMatrix = Float64List.fromList([ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, -]); diff --git a/testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj b/testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj index feecb3b772466..5ef94a102a778 100644 --- a/testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj +++ b/testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj @@ -37,8 +37,11 @@ 6816DB9E231750ED00A51400 /* GoldenPlatformViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DB9D231750ED00A51400 /* GoldenPlatformViewTests.m */; }; 6816DBA12317573300A51400 /* GoldenImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DBA02317573300A51400 /* GoldenImage.m */; }; 6816DBA42318358200A51400 /* GoldenTestManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DBA32318358200A51400 /* GoldenTestManager.m */; }; + 687AF8E9291EBDE0003912C7 /* golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 687AF8E8291EBDE0003912C7 /* golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png */; }; 68A5B63423EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68A5B63323EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m */; }; 68D4017D2564859300ECD91A /* ContinuousTexture.m in Sources */ = {isa = PBXBuildFile; fileRef = 68D4017C2564859300ECD91A /* ContinuousTexture.m */; }; + 68D5003F291ED645001ACFE1 /* golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 68D5003D291ED645001ACFE1 /* golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png */; }; + 68D50042291ED8CD001ACFE1 /* golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 68D50041291ED8CD001ACFE1 /* golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png */; }; F26F15B8268B6B5600EC54D3 /* iPadGestureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F26F15B7268B6B5500EC54D3 /* iPadGestureTests.m */; }; F769EB53276312BB007AC10F /* golden_platform_view_cliprect_iPhone 8_13.0_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = F769EB52276312BB007AC10F /* golden_platform_view_cliprect_iPhone 8_13.0_simulator.png */; }; F7B464EB2759D0A900079189 /* golden_two_platform_views_with_other_backdrop_filter_iPhone 8_13.0_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = F7B464DE2759D0A900079189 /* golden_two_platform_views_with_other_backdrop_filter_iPhone 8_13.0_simulator.png */; }; @@ -148,9 +151,12 @@ 6816DBA02317573300A51400 /* GoldenImage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoldenImage.m; sourceTree = ""; }; 6816DBA22318358200A51400 /* GoldenTestManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoldenTestManager.h; sourceTree = ""; }; 6816DBA32318358200A51400 /* GoldenTestManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoldenTestManager.m; sourceTree = ""; }; + 687AF8E8291EBDE0003912C7 /* golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png"; sourceTree = ""; }; 68A5B63323EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformViewGestureRecognizerTests.m; sourceTree = ""; }; 68D4017B2564859300ECD91A /* ContinuousTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContinuousTexture.h; sourceTree = ""; }; 68D4017C2564859300ECD91A /* ContinuousTexture.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContinuousTexture.m; sourceTree = ""; }; + 68D5003D291ED645001ACFE1 /* golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png"; sourceTree = ""; }; + 68D50041291ED8CD001ACFE1 /* golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png"; sourceTree = ""; }; F26F15B7268B6B5500EC54D3 /* iPadGestureTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iPadGestureTests.m; sourceTree = ""; }; F72114B628EF99F500184A2D /* Info_Impeller.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info_Impeller.plist; sourceTree = ""; }; F769EB52276312BB007AC10F /* golden_platform_view_cliprect_iPhone 8_13.0_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprect_iPhone 8_13.0_simulator.png"; sourceTree = ""; }; @@ -290,6 +296,9 @@ F7B464DC2759D02B00079189 /* Goldens */ = { isa = PBXGroup; children = ( + 68D50041291ED8CD001ACFE1 /* golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png */, + 68D5003D291ED645001ACFE1 /* golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png */, + 687AF8E8291EBDE0003912C7 /* golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png */, F7B464E32759D0A900079189 /* golden_bogus_font_text_iPhone 8_13.0_simulator.png */, F7B464E92759D0A900079189 /* golden_non_full_screen_flutter_view_platform_view_iPhone 8_13.0_simulator.png */, F7B464E52759D0A900079189 /* golden_platform_view_clippath_iPhone 8_13.0_simulator.png */, @@ -432,6 +441,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 68D50042291ED8CD001ACFE1 /* golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png in Resources */, F7B464F62759D0A900079189 /* golden_non_full_screen_flutter_view_platform_view_iPhone 8_13.0_simulator.png in Resources */, F7B464F02759D0A900079189 /* golden_bogus_font_text_iPhone 8_13.0_simulator.png in Resources */, F7B464F22759D0A900079189 /* golden_platform_view_clippath_iPhone 8_13.0_simulator.png in Resources */, @@ -442,8 +452,10 @@ F7B464F32759D0A900079189 /* golden_platform_view_multiple_background_foreground_iPhone 8_13.0_simulator.png in Resources */, F7B464F72759D0A900079189 /* golden_platform_view_rotate_iPhone 8_13.0_simulator.png in Resources */, F7B464ED2759D0A900079189 /* golden_platform_view_cliprrect_iPhone 8_13.0_simulator.png in Resources */, + 68D5003F291ED645001ACFE1 /* golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png in Resources */, F7B464EB2759D0A900079189 /* golden_two_platform_views_with_other_backdrop_filter_iPhone 8_13.0_simulator.png in Resources */, F7B464F42759D0A900079189 /* golden_platform_view_with_other_backdrop_filter_iPhone 8_13.0_simulator.png in Resources */, + 687AF8E9291EBDE0003912C7 /* golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png in Resources */, F769EB53276312BB007AC10F /* golden_platform_view_cliprect_iPhone 8_13.0_simulator.png in Resources */, F7B464EF2759D0A900079189 /* golden_platform_view_multiple_iPhone 8_13.0_simulator.png in Resources */, ); diff --git a/testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m b/testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m index f69b402fa7131..4674126c7b47e 100644 --- a/testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m +++ b/testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m @@ -44,6 +44,9 @@ - (BOOL)application:(UIApplication*)application @"--platform-view-cliprect" : @"platform_view_cliprect", @"--platform-view-cliprrect" : @"platform_view_cliprrect", @"--platform-view-clippath" : @"platform_view_clippath", + @"--platform-view-cliprrect-with-transform" : @"platform_view_cliprrect_with_transform", + @"--platform-view-cliprect-with-transform" : @"platform_view_cliprect_with_transform", + @"--platform-view-clippath-with-transform" : @"platform_view_clippath_with_transform", @"--platform-view-transform" : @"platform_view_transform", @"--platform-view-opacity" : @"platform_view_opacity", @"--platform-view-with-other-backdrop-filter" : @"platform_view_with_other_backdrop_filter", diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenTestManager.m b/testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenTestManager.m index 4b6f15e5e85c0..ad1a400bb7d9a 100644 --- a/testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenTestManager.m +++ b/testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenTestManager.m @@ -30,6 +30,9 @@ - (instancetype)initWithLaunchArg:(NSString*)launchArg { @"--platform-view-cliprect" : @"platform_view_cliprect", @"--platform-view-cliprrect" : @"platform_view_cliprrect", @"--platform-view-clippath" : @"platform_view_clippath", + @"--platform-view-cliprrect-with-transform" : @"platform_view_cliprrect_with_transform", + @"--platform-view-cliprect-with-transform" : @"platform_view_cliprect_with_transform", + @"--platform-view-clippath-with-transform" : @"platform_view_clippath_with_transform", @"--platform-view-transform" : @"platform_view_transform", @"--platform-view-opacity" : @"platform_view_opacity", @"--platform-view-with-other-backdrop-filter" : @"platform_view_with_other_backdrop_filter", diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m b/testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m index 4da67c0ab1a72..cfec0aa1ca84b 100644 --- a/testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m +++ b/testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m @@ -134,6 +134,60 @@ - (void)testPlatformView { @end +@interface PlatformViewMutationClipRectWithTransformTests : GoldenPlatformViewTests + +@end + +@implementation PlatformViewMutationClipRectWithTransformTests + +- (instancetype)initWithInvocation:(NSInvocation*)invocation { + GoldenTestManager* manager = + [[GoldenTestManager alloc] initWithLaunchArg:@"--platform-view-cliprect-with-transform"]; + return [super initWithManager:manager invocation:invocation]; +} + +- (void)testPlatformView { + [self checkPlatformViewGolden]; +} + +@end + +@interface PlatformViewMutationClipRRectWithTransformTests : GoldenPlatformViewTests + +@end + +@implementation PlatformViewMutationClipRRectWithTransformTests + +- (instancetype)initWithInvocation:(NSInvocation*)invocation { + GoldenTestManager* manager = + [[GoldenTestManager alloc] initWithLaunchArg:@"--platform-view-cliprrect-with-transform"]; + return [super initWithManager:manager invocation:invocation]; +} + +- (void)testPlatformView { + [self checkPlatformViewGolden]; +} + +@end + +@interface PlatformViewMutationClipPathWithTransformTests : GoldenPlatformViewTests + +@end + +@implementation PlatformViewMutationClipPathWithTransformTests + +- (instancetype)initWithInvocation:(NSInvocation*)invocation { + GoldenTestManager* manager = + [[GoldenTestManager alloc] initWithLaunchArg:@"--platform-view-clippath-with-transform"]; + return [super initWithManager:manager invocation:invocation]; +} + +- (void)testPlatformView { + [self checkPlatformViewGolden]; +} + +@end + @interface PlatformViewMutationTransformTests : GoldenPlatformViewTests @end diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png b/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png new file mode 100644 index 0000000000000..b494f84298ea5 Binary files /dev/null and b/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_clippath_with_transform_iPhone 8_13.0_simulator.png differ diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png b/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png new file mode 100644 index 0000000000000..883528a188218 Binary files /dev/null and b/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_cliprect_with_transform_iPhone 8_13.0_simulator.png differ diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png b/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png new file mode 100644 index 0000000000000..b3adaa22e1b3c Binary files /dev/null and b/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_platform_view_cliprrect_with_transform_iPhone 8_13.0_simulator.png differ diff --git a/testing/scenario_app/lib/src/platform_view.dart b/testing/scenario_app/lib/src/platform_view.dart index 11d2267942779..7e989b6998ed8 100644 --- a/testing/scenario_app/lib/src/platform_view.dart +++ b/testing/scenario_app/lib/src/platform_view.dart @@ -620,7 +620,7 @@ class PlatformViewClipRRectScenario extends PlatformViewScenario { /// Platform view with clip path. class PlatformViewClipPathScenario extends PlatformViewScenario { - /// Constructs a platform view with clip rrect scenario. + /// Constructs a platform view with clip path scenario. PlatformViewClipPathScenario( PlatformDispatcher dispatcher, { int id = 0, @@ -645,6 +645,135 @@ class PlatformViewClipPathScenario extends PlatformViewScenario { } } +/// Platform view with clip rect after transformed. +class PlatformViewClipRectWithTransformScenario extends PlatformViewScenario { + /// Constructs a platform view with clip rect with transform scenario. + PlatformViewClipRectWithTransformScenario( + PlatformDispatcher dispatcher, { + int id = 0, + }) : super(dispatcher, id: id); + + @override + void onBeginFrame(Duration duration) { + final Matrix4 matrix4 = Matrix4.identity() + ..rotateZ(1) + ..scale(0.5, 0.5, 1.0) + ..translate(1000.0, 100.0); + + final SceneBuilder builder = SceneBuilder()..pushTransform(matrix4.storage); + builder.pushClipRect(const Rect.fromLTRB(100, 100, 400, 400)); + + addPlatformView( + id, + dispatcher: dispatcher, + sceneBuilder: builder, + ); + + // Add a translucent rect that has the same size of PlatformView. + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.drawRect( + const Rect.fromLTWH(0, 0, 500, 500), + Paint()..color = const Color(0x22FF0000), + ); + final Picture picture = recorder.endRecording(); + builder.addPicture(Offset.zero, picture); + + finishBuilder(builder); + } +} + +/// Platform view with clip rrect after transformed. +class PlatformViewClipRRectWithTransformScenario extends PlatformViewScenario { + /// Constructs a platform view with clip rrect with transform scenario. + PlatformViewClipRRectWithTransformScenario( + PlatformDispatcher dispatcher, { + int id = 0, + }) : super(dispatcher, id: id); + + @override + void onBeginFrame(Duration duration) { + final Matrix4 matrix4 = Matrix4.identity() + ..rotateZ(1) + ..scale(0.5, 0.5, 1.0) + ..translate(1000.0, 100.0); + + final SceneBuilder builder = SceneBuilder()..pushTransform(matrix4.storage); + builder.pushClipRRect( + RRect.fromLTRBAndCorners( + 100, + 100, + 400, + 400, + topLeft: const Radius.circular(15), + topRight: const Radius.circular(50), + bottomLeft: const Radius.circular(50), + ), + ); + addPlatformView( + id, + dispatcher: dispatcher, + sceneBuilder: builder, + ); + + // Add a translucent rect that has the same size of PlatformView. + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.drawRect( + const Rect.fromLTWH(0, 0, 500, 500), + Paint()..color = const Color(0x22FF0000), + ); + final Picture picture = recorder.endRecording(); + builder.addPicture(Offset.zero, picture); + + finishBuilder(builder); + } +} + +/// Platform view with clip path after transformed. +class PlatformViewClipPathWithTransformScenario extends PlatformViewScenario { + /// Constructs a platform view with clip path with transform scenario. + PlatformViewClipPathWithTransformScenario( + PlatformDispatcher dispatcher, { + int id = 0, + }) : super(dispatcher, id: id); + + @override + void onBeginFrame(Duration duration) { + final Matrix4 matrix4 = Matrix4.identity() + ..rotateZ(1) + ..scale(0.5, 0.5, 1.0) + ..translate(1000.0, 100.0); + + final SceneBuilder builder = SceneBuilder()..pushTransform(matrix4.storage); + final Path path = Path() + ..moveTo(100, 100) + ..quadraticBezierTo(50, 250, 100, 400) + ..lineTo(350, 400) + ..cubicTo(400, 300, 300, 200, 350, 100) + ..close(); + + builder.pushClipPath(path); + addPlatformView( + id, + dispatcher: dispatcher, + sceneBuilder: builder, + ); + + // Add a translucent rect that has the same size of PlatformView. + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.drawRect( + const Rect.fromLTWH(0, 0, 500, 500), + Paint()..color = const Color(0x22FF0000), + ); + final Picture picture = recorder.endRecording(); + builder.addPicture(Offset.zero, picture); + + finishBuilder(builder); + } +} + /// Platform view with transform. class PlatformViewTransformScenario extends PlatformViewScenario { /// Constructs a platform view with transform scenario. diff --git a/testing/scenario_app/lib/src/scenarios.dart b/testing/scenario_app/lib/src/scenarios.dart index cbf4e6f528658..c992eea814fcd 100644 --- a/testing/scenario_app/lib/src/scenarios.dart +++ b/testing/scenario_app/lib/src/scenarios.dart @@ -31,8 +31,11 @@ Map _scenarios = { 'platform_view_multiple_without_overlays': () => MultiPlatformViewWithoutOverlaysScenario(PlatformDispatcher.instance, firstId: _viewId++, secondId: _viewId++), 'platform_view_max_overlays': () => PlatformViewMaxOverlaysScenario(PlatformDispatcher.instance, id: _viewId++), 'platform_view_cliprect': () => PlatformViewClipRectScenario(PlatformDispatcher.instance, id: _viewId++), + 'platform_view_cliprect_with_transform': () => PlatformViewClipRectWithTransformScenario(PlatformDispatcher.instance, id: _viewId++), 'platform_view_cliprrect': () => PlatformViewClipRRectScenario(PlatformDispatcher.instance, id: _viewId++), + 'platform_view_cliprrect_with_transform': () => PlatformViewClipRRectWithTransformScenario(PlatformDispatcher.instance, id: _viewId++), 'platform_view_clippath': () => PlatformViewClipPathScenario(PlatformDispatcher.instance, id: _viewId++), + 'platform_view_clippath_with_transform': () => PlatformViewClipPathWithTransformScenario(PlatformDispatcher.instance, id: _viewId++), 'platform_view_transform': () => PlatformViewTransformScenario(PlatformDispatcher.instance, id: _viewId++), 'platform_view_opacity': () => PlatformViewOpacityScenario(PlatformDispatcher.instance, id: _viewId++), 'platform_view_with_other_backdrop_filter': () => PlatformViewWithOtherBackDropFilter(PlatformDispatcher.instance, id: _viewId++), diff --git a/third_party/accessibility/ax/ax_enum_util_unittest.cc b/third_party/accessibility/ax/ax_enum_util_unittest.cc index 8f64916b78379..b5760f30011a5 100644 --- a/third_party/accessibility/ax/ax_enum_util_unittest.cc +++ b/third_party/accessibility/ax/ax_enum_util_unittest.cc @@ -144,7 +144,8 @@ TEST(AXEnumUtilTest, MarkerType) { // 8 (Composition) is // explicitly skipped in // ax_enums.mojom. - val == 4 ? 16 : val * 2; + val == 4 ? 16 + : val * 2; }); } diff --git a/third_party/accessibility/base/numerics/safe_conversions_arm_impl.h b/third_party/accessibility/base/numerics/safe_conversions_arm_impl.h index c94947d42d9c4..cf31072b9b89e 100644 --- a/third_party/accessibility/base/numerics/safe_conversions_arm_impl.h +++ b/third_party/accessibility/base/numerics/safe_conversions_arm_impl.h @@ -30,18 +30,16 @@ struct SaturateFastAsmOp { uint32_t>::type result; if (std::is_signed::value) { asm("ssat %[dst], %[shift], %[src]" - : [ dst ] "=r"(result) - : - [ src ] "r"(src), [ shift ] "n"(IntegerBitsPlusSign::value <= 32 - ? IntegerBitsPlusSign::value - : 32)); + : [dst] "=r"(result) + : [src] "r"(src), [shift] "n"(IntegerBitsPlusSign::value <= 32 + ? IntegerBitsPlusSign::value + : 32)); } else { asm("usat %[dst], %[shift], %[src]" - : [ dst ] "=r"(result) - : - [ src ] "r"(src), [ shift ] "n"(IntegerBitsPlusSign::value < 32 - ? IntegerBitsPlusSign::value - : 31)); + : [dst] "=r"(result) + : [src] "r"(src), [shift] "n"(IntegerBitsPlusSign::value < 32 + ? IntegerBitsPlusSign::value + : 31)); } return static_cast(result); } diff --git a/third_party/accessibility/base/numerics/safe_math_arm_impl.h b/third_party/accessibility/base/numerics/safe_math_arm_impl.h index f8abca7f4f9e9..ff86bd0b73b5f 100644 --- a/third_party/accessibility/base/numerics/safe_math_arm_impl.h +++ b/third_party/accessibility/base/numerics/safe_math_arm_impl.h @@ -61,8 +61,8 @@ struct ClampedAddFastAsmOp { int32_t y_i32 = checked_cast(y); asm("qadd %[result], %[first], %[second]" - : [ result ] "=r"(result) - : [ first ] "r"(x_i32), [ second ] "r"(y_i32)); + : [result] "=r"(result) + : [first] "r"(x_i32), [second] "r"(y_i32)); return saturated_cast(result); } }; @@ -87,8 +87,8 @@ struct ClampedSubFastAsmOp { int32_t y_i32 = checked_cast(y); asm("qsub %[result], %[first], %[second]" - : [ result ] "=r"(result) - : [ first ] "r"(x_i32), [ second ] "r"(y_i32)); + : [result] "=r"(result) + : [first] "r"(x_i32), [second] "r"(y_i32)); return saturated_cast(result); } }; diff --git a/third_party/accessibility/base/test/gtest_util.h b/third_party/accessibility/base/test/gtest_util.h index c96ccaa504986..de3f9b9d93add 100644 --- a/third_party/accessibility/base/test/gtest_util.h +++ b/third_party/accessibility/base/test/gtest_util.h @@ -37,7 +37,7 @@ #define EXPECT_DCHECK_DEATH(statement) \ GTEST_UNSUPPORTED_DEATH_TEST(statement, "Check failed", ) #define ASSERT_DCHECK_DEATH(statement) \ - GTEST_UNSUPPORTED_DEATH_TEST(statement, "Check failed", return ) + GTEST_UNSUPPORTED_DEATH_TEST(statement, "Check failed", return) #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) && !defined(NDEBUG) @@ -61,7 +61,7 @@ #define EXPECT_CHECK_DEATH(statement) \ GTEST_UNSUPPORTED_DEATH_TEST(statement, "", ) #define ASSERT_CHECK_DEATH(statement) \ - GTEST_UNSUPPORTED_DEATH_TEST(statement, "", return ) + GTEST_UNSUPPORTED_DEATH_TEST(statement, "", return) #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) diff --git a/third_party/tonic/dart_binding_macros.h b/third_party/tonic/dart_binding_macros.h index f1a2ad6e9beb9..abb30c1f156c5 100644 --- a/third_party/tonic/dart_binding_macros.h +++ b/third_party/tonic/dart_binding_macros.h @@ -27,10 +27,10 @@ {#CLASS "_" #METHOD, CLASS##_##METHOD, \ tonic::IndicesForSignature::count + 1, true}, -#define DART_REGISTER_NATIVE_STATIC(CLASS, METHOD) \ - { \ -#CLASS "_" #METHOD, CLASS##_##METHOD, \ - tonic::IndicesForSignature < decltype(&CLASS::METHOD)> ::count, true \ +#define DART_REGISTER_NATIVE_STATIC(CLASS, METHOD) \ + { \ + #CLASS "_" #METHOD, CLASS##_##METHOD, \ + tonic::IndicesForSignature::count, true \ } #define DART_BIND_ALL(CLASS, FOR_EACH) \ diff --git a/third_party/web_unicode/LICENSE b/third_party/web_unicode/LICENSE new file mode 100644 index 0000000000000..85d0d580d230c --- /dev/null +++ b/third_party/web_unicode/LICENSE @@ -0,0 +1,46 @@ +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +See Terms of Use +for definitions of Unicode Inc.’s Data Files and Software. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2022 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in https://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 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 THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. diff --git a/third_party/web_unicode/README.md b/third_party/web_unicode/README.md new file mode 100644 index 0000000000000..bb3922d50e330 --- /dev/null +++ b/third_party/web_unicode/README.md @@ -0,0 +1,25 @@ +## Usage ## + +To generate code for line/word break properties, follow these steps: + +### 1. **Download the unicode files:** + +The properties files can be found on the unicode.org website, for example [LineBreak.txt](https://www.unicode.org/Public/13.0.0/ucd/LineBreak.txt) and [WordBreakProperty.txt](https://www.unicode.org/Public/13.0.0/ucd/auxiliary/WordBreakProperty.txt). The codegen script expects the files to be located at `third_party/web_unicode/properties/`. + +### 2. **Run the codegen script:** + +Inside the `third_party/web_unicode` directory: +``` +dart tool/unicode_sync_script.dart +``` + +## Check Mode ## + +If you don't want to generate code, but you want to make sure that the properties files and the codegen files are still in sync, you can run the codegen script in "check mode". + +Inside the `third_party/web_unicode` directory: +``` +dart tool/unicode_sync_script.dart --check +``` + +This command won't overwite the existing codegen files. It only checks whether they are still in sync with the properties files or not. If not, it exits with a non-zero exit code. diff --git a/third_party/web_unicode/lib/web_unicode.dart b/third_party/web_unicode/lib/web_unicode.dart new file mode 100644 index 0000000000000..a1dc084549c0a --- /dev/null +++ b/third_party/web_unicode/lib/web_unicode.dart @@ -0,0 +1,8 @@ +// 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. + +library web_unicode; + +export 'web_unicode/codegen/line_break_properties.dart'; +export 'web_unicode/codegen/word_break_properties.dart'; diff --git a/third_party/web_unicode/lib/web_unicode/codegen/line_break_properties.dart b/third_party/web_unicode/lib/web_unicode/codegen/line_break_properties.dart new file mode 100644 index 0000000000000..23305282228a3 --- /dev/null +++ b/third_party/web_unicode/lib/web_unicode/codegen/line_break_properties.dart @@ -0,0 +1,61 @@ +// Copyright 2022 Google LLC +// +// For terms of use, see https://www.unicode.org/copyright.html + +// AUTO-GENERATED FILE. +// Generated by: tool/unicode_sync_script.dart + +// ignore_for_file: public_member_api_docs + +/// For an explanation of these enum values, see: +/// +/// * https://www.unicode.org/reports/tr14/tr14-45.html#DescriptionOfProperties +enum LineCharProperty { + CM, // serialized as "A" + BA, // serialized as "B" + LF, // serialized as "C" + // Normalized from: NL + BK, // serialized as "D" + CR, // serialized as "E" + SP, // serialized as "F" + EX, // serialized as "G" + QU, // serialized as "H" + // Normalized from: AI, SA, SG, XX + AL, // serialized as "I" + PR, // serialized as "J" + PO, // serialized as "K" + OP, // serialized as "L" + CP, // serialized as "M" + IS, // serialized as "N" + HY, // serialized as "O" + SY, // serialized as "P" + NU, // serialized as "Q" + CL, // serialized as "R" + GL, // serialized as "S" + BB, // serialized as "T" + HL, // serialized as "U" + JL, // serialized as "V" + JV, // serialized as "W" + JT, // serialized as "X" + // Normalized from: CJ + NS, // serialized as "Y" + ZW, // serialized as "Z" + ZWJ, // serialized as "a" + B2, // serialized as "b" + IN, // serialized as "c" + WJ, // serialized as "d" + ID, // serialized as "e" + EB, // serialized as "f" + H2, // serialized as "g" + H3, // serialized as "h" + CB, // serialized as "i" + RI, // serialized as "j" + EM, // serialized as "k" +} + +const String packedLineBreakProperties = + '00000008A0009!B000a!C000b000cD000d!E000e000vA000w!F000x!G000y!H000z!I0010!J0011!K0012!I0013!H0014!L0015!M0016!I0017!J0018!N0019!O001a!N001b!P001c001lQ001m001nN001o001qI001r!G001s002iI002j!L002k!J002l!M002m003eI003f!L003g!B003h!R003i!I003j003oA003p!D003q004fA004g!S004h!L004i!K004j004lJ004m004qI004r!H004s!I004t!B004u004vI004w!K004x!J004y004zI0050!T00510056I0057!H0058005aI005b!L005c00jrI00js!T00jt00jvI00jw!T00jx00keI00kf!T00kg00lbI00lc00niA00nj!S00nk00nvA00nw00o2S00o300ofA00og00otI00ou!N00ov00w2I00w300w9A00wa013cI013d!N013e!B013h013iI013j!J013l014tA014u!B014v!A014w!I014x014yA014z!I01500151A0152!G0153!A015c0162U0167016aU016b016wI016x016zK01700171N01720173I0174017eA017f!G017g!A017i017jG017k018qI018r019bA019c019lQ019m!K019n019oQ019p019rI019s!A019t01cjI01ck!G01cl!I01cm01csA01ct01cuI01cv01d0A01d101d2I01d301d4A01d5!I01d601d9A01da01dbI01dc01dlQ01dm01e8I01e9!A01ea01f3I01f401fuA01fx01idI01ie01ioA01ip!I01j401jdQ01je01kaI01kb01kjA01kk01knI01ko!N01kp!G01kq!I01kt!A01ku01kvJ01kw01lhI01li01llA01lm!I01ln01lvA01lw!I01lx01lzA01m0!I01m101m5A01m801ncI01nd01nfA01ni01qfI01qr01r5A01r6!I01r701s3A01s401tlI01tm01toA01tp!I01tq01u7A01u8!I01u901ufA01ug01upI01uq01urA01us01utB01uu01v3Q01v401vkI01vl01vnA01vp01x5I01x8!A01x9!I01xa01xgA01xj01xkA01xn01xpA01xq!I01xz!A01y401y9I01ya01ybA01ye01ynQ01yo01ypI01yq01yrK01ys01ywI01yx!K01yy!I01yz!J01z001z1I01z2!A01z501z7A01z9020pI020s!A020u020yA02130214A02170219A021d!A021l021qI021y0227Q02280229A022a022cI022d!A022e!I022p022rA022t0249I024c!A024d!I024e024lA024n024pA024r024tA024w025dI025e025fA025i025rQ025s!I025t!J0261!I02620267A0269026bA026d027tI027w!A027x!I027y0284A02870288A028b028dA028l028nA028s028xI028y028zA0292029bQ029c029jI029u!A029v02bdI02bi02bmA02bq02bsA02bu02bxA02c0!I02c7!A02cm02cvQ02cw02d4I02d5!J02d6!I02dc02dgA02dh02f1I02f202f8A02fa02fcA02fe02fhA02fp02fqA02fs02g1I02g202g3A02g602gfQ02gn!T02go02gwI02gx02gzA02h0!T02h102ihI02ik!A02il!I02im02isA02iu02iwA02iy02j1A02j902jaA02ji02jlI02jm02jnA02jq02jzQ02k102k2I02kg02kjA02kk02m2I02m302m4A02m5!I02m602mcA02me02mgA02mi02mlA02mm02muI02mv!A02mw02n5I02n602n7A02na02njQ02nk02nsI02nt!K02nu02nzI02o102o3A02o502pyI02q2!A02q702qcA02qe!A02qg02qnA02qu02r3Q02r602r7A02r802t6I02tb!J02tc02trI02ts02u1Q02u202u3B02v502x9I02xc02xlQ02xo02yoI02yp02ysT02yt!I02yu02yvT02yw!S02yx02yyT02yz!B02z0!S02z102z5G02z6!S02z7!I02z8!G02z902zbI02zc02zdA02ze02zjI02zk02ztQ02zu0303I0304!B0305!A0306!I0307!A0308!I0309!A030a!L030b!R030c!L030d!R030e030fA030g031oI031t0326A0327!B0328032cA032d!B032e032fA032g032kI032l032vA032x033wA033y033zB03400345I0346!A0347034fI034g034hT034i!B034j!T034k034oI034p034qS035s037jI037k037tQ037u037vB037w039rI039s03a1Q03a203cvI03cw03fjV03fk03hjW03hk03jzX03k003tmI03tp03trA03ts!I03tt!B03tu03y5I03y8!B03y904fzI04g0!B04g104gqI04gr!L04gs!R04gw04iyI04iz04j1B04j204k1I04k204k4A04kg04kxI04ky04l0A04l104l2B04lc04ltI04lu04lvA04m804moI04mq04mrA04n404pfI04pg04phB04pi!Y04pj!I04pk!B04pl!I04pm!B04pn!J04po04ppI04ps04q1Q04q804qpI04qq04qrG04qs04qtB04qu!T04qv!I04qw04qxG04qy!I04qz04r1A04r2!S04r404rdQ04rk04ucI04ud04ueA04uf04vcI04vd!A04ve04ymI04yo04yzA04z404zfA04zk!I04zo04zpG04zq04zzQ0500053dI053k053tQ053u055iI055j055nA055q058cI058f!A058g058pQ058w0595Q059c059pI059s05a8A05c005c4A05c505dfI05dg05dwA05dx05e3I05e805ehQ05ei05ejB05ek!I05el05eoB05ep05eyI05ez05f7A05f805fgI05fk05fmA05fn05ggI05gh05gtA05gu05gvI05gw05h5Q05h605idI05ie05irA05j005k3I05k405knA05kr05kvB05kw05l5Q05l905lbI05lc05llQ05lm05mlI05mm05mnB05mo05onI05ow05oyA05oz!I05p005pkA05pl05poI05pp!A05pq05pvI05pw!A05px05pyI05pz05q1A05q205vjI05vk05x5A05x705xbA05xc06bgI06bh!T06bi!I06bk06bqB06br!S06bs06buB06bv!Z06bw!A06bx!a06by06bzA06c0!B06c1!S06c206c3B06c4!b06c506c7I06c806c9H06ca!L06cb06cdH06ce!L06cf!H06cg06cjI06ck06cmc06cn!B06co06cpD06cq06cuA06cv!S06cw06d3K06d4!I06d506d6H06d7!I06d806d9Y06da06dfI06dg!N06dh!L06di!R06dj06dlY06dm06dxI06dy!B06dz!I06e006e3B06e4!I06e506e7B06e8!d06e906ecI06ee06enA06eo06f0I06f1!L06f2!R06f306fgI06fh!L06fi!R06fk06fwI06g006g6J06g7!K06g806glJ06gm!K06gn06gqJ06gr!K06gs06gtJ06gu!K06gv06hbJ06hc06i8A06io06iqI06ir!K06is06iwI06ix!K06iy06j9I06ja!J06jb06q9I06qa06qbJ06qc06weI06wf!c06wg06x3I06x4!L06x5!R06x6!L06x7!R06x806xlI06xm06xne06xo06y0I06y1!L06y2!R06y3073jI073k073ne073o07i7I07i807ibe07ic07irI07is07ite07iu07ivI07iw!e07ix!I07iy07j0e07j1!f07j207j3e07j407jsI07jt07jve07jw07l3I07l4!e07l507lqI07lr!e07ls07ngI07nh07nse07nt07nwI07nx!e07ny!I07nz07o1e07o2!I07o307o4e07o507o7I07o807o9e07oa07obI07oc!e07od07oeI07of07ohe07oi07opI07oq!e07or07owI07ox07p1e07p2!I07p307p4e07p5!f07p6!e07p707p8I07p907pge07ph07pjI07pk07ple07pm07ppf07pq07ruI07rv07s0H07s1!I07s207s3G07s4!e07s507s7I07s8!L07s9!R07sa!L07sb!R07sc!L07sd!R07se!L07sf!R07sg!L07sh!R07si!L07sj!R07sk!L07sl!R07sm07usI07ut!L07uu!R07uv07vpI07vq!L07vr!R07vs!L07vt!R07vu!L07vv!R07vw!L07vx!R07vy!L07vz!R07w00876I0877!L0878!R0879!L087a!R087b!L087c!R087d!L087e!R087f!L087g!R087h!L087i!R087j!L087k!R087l!L087m!R087n!L087o!R087p!L087q!R087r!L087s!R087t089jI089k!L089l!R089m!L089n!R089o08ajI08ak!L08al!R08am08viI08vj08vlA08vm08vnI08vt!G08vu08vwB08vx!I08vy!G08vz!B08w008z3I08z4!B08zj!A08zk0926I09280933A0934093hH093i093pB093q!I093r!B093s!L093t!B093u093vI093w093xH093y093zI09400941H0942!L0943!R0944!L0945!R0946!L0947!R0948!L0949!R094a094dB094e!G094f!I094g094hB094i!I094j094kB094l094pI094q094rb094s094uB094v!I094w094xB094y!L094z0956B0957!I0958!B0959!I095a095bB095c095eI096o097de097f099ve09a809g5e09gw09h7e09hc!B09hd09heR09hf09hge09hh!Y09hi09hje09hk!L09hl!R09hm!L09hn!R09ho!L09hp!R09hq!L09hr!R09hs!L09ht!R09hu09hve09hw!L09hx!R09hy!L09hz!R09i0!L09i1!R09i2!L09i3!R09i4!Y09i5!L09i609i7R09i809ihe09ii09inA09io09ise09it!A09iu09iye09iz09j0Y09j109j3e09j5!Y09j6!e09j7!Y09j8!e09j9!Y09ja!e09jb!Y09jc!e09jd!Y09je09k2e09k3!Y09k409kye09kz!Y09l0!e09l1!Y09l2!e09l3!Y09l409l9e09la!Y09lb09lge09lh09liY09ll09lmA09ln09lqY09lr!e09ls09ltY09lu!e09lv!Y09lw!e09lx!Y09ly!e09lz!Y09m0!e09m1!Y09m209mqe09mr!Y09ms09nme09nn!Y09no!e09np!Y09nq!e09nr!Y09ns09nxe09ny!Y09nz09o4e09o509o6Y09o709oae09ob09oeY09of!e09ol09pre09pt09see09sg09ure09v409vjY09vk09wee09wg09xje09xk09xrI09xs0fcve0fcw0fenI0feo0vmce0vmd!Y0vme0wi4e0wi80wjqe0wk00wl9I0wla0wlbB0wlc0wssI0wst!B0wsu!G0wsv!B0wsw0wtbI0wtc0wtlQ0wtm0wviI0wvj0wvmA0wvn!I0wvo0wvxA0wvy0wwtI0wwu0wwvA0www0wz3I0wz40wz5A0wz6!I0wz70wzbB0wzk0x6pI0x6q!A0x6r0x6tI0x6u!A0x6v0x6yI0x6z!A0x700x7mI0x7n0x7rA0x7s0x7vI0x7w!A0x800x87I0x88!K0x890x9vI0x9w0x9xT0x9y0x9zG0xa80xa9A0xaa0xbnI0xbo0xc5A0xce0xcfB0xcg0xcpQ0xcw0xddA0xde0xdnI0xdo!T0xdp0xdqI0xdr!A0xds0xe1Q0xe20xetI0xeu0xf1A0xf20xf3B0xf40xfqI0xfr0xg3A0xgf!I0xgg0xh8V0xhc0xhfA0xhg0xiqI0xir0xj4A0xj50xjaI0xjb0xjdB0xje0xjjI0xjk0xjtQ0xjy0xkfI0xkg0xkpQ0xkq0xm0I0xm10xmeA0xmo0xmqI0xmr!A0xms0xmzI0xn00xn1A0xn40xndQ0xng!I0xnh0xnjB0xnk0xreI0xrf0xrjA0xrk0xrlB0xrm0xroI0xrp0xrqA0xs10xyaI0xyb0xyiA0xyj!B0xyk0xylA0xyo0xyxQ0xz4!g0xz50xzvh0xzw!g0xzx0y0nh0y0o!g0y0p0y1fh0y1g!g0y1h0y27h0y28!g0y290y2zh0y30!g0y310y3rh0y3s!g0y3t0y4jh0y4k!g0y4l0y5bh0y5c!g0y5d0y63h0y64!g0y650y6vh0y6w!g0y6x0y7nh0y7o!g0y7p0y8fh0y8g!g0y8h0y97h0y98!g0y990y9zh0ya0!g0ya10yarh0yas!g0yat0ybjh0ybk!g0ybl0ycbh0ycc!g0ycd0yd3h0yd4!g0yd50ydvh0ydw!g0ydx0yenh0yeo!g0yep0yffh0yfg!g0yfh0yg7h0yg8!g0yg90ygzh0yh0!g0yh10yhrh0yhs!g0yht0yijh0yik!g0yil0yjbh0yjc!g0yjd0yk3h0yk4!g0yk50ykvh0ykw!g0ykx0ylnh0ylo!g0ylp0ymfh0ymg!g0ymh0yn7h0yn8!g0yn90ynzh0yo0!g0yo10yorh0yos!g0yot0ypjh0ypk!g0ypl0yqbh0yqc!g0yqd0yr3h0yr4!g0yr50yrvh0yrw!g0yrx0ysnh0yso!g0ysp0ytfh0ytg!g0yth0yu7h0yu8!g0yu90yuzh0yv0!g0yv10yvrh0yvs!g0yvt0ywjh0ywk!g0ywl0yxbh0yxc!g0yxd0yy3h0yy4!g0yy50yyvh0yyw!g0yyx0yznh0yzo!g0yzp0z0fh0z0g!g0z0h0z17h0z18!g0z190z1zh0z20!g0z210z2rh0z2s!g0z2t0z3jh0z3k!g0z3l0z4bh0z4c!g0z4d0z53h0z54!g0z550z5vh0z5w!g0z5x0z6nh0z6o!g0z6p0z7fh0z7g!g0z7h0z87h0z88!g0z890z8zh0z90!g0z910z9rh0z9s!g0z9t0zajh0zak!g0zal0zbbh0zbc!g0zbd0zc3h0zc4!g0zc50zcvh0zcw!g0zcx0zdnh0zdo!g0zdp0zefh0zeg!g0zeh0zf7h0zf8!g0zf90zfzh0zg0!g0zg10zgrh0zgs!g0zgt0zhjh0zhk!g0zhl0zibh0zic!g0zid0zj3h0zj4!g0zj50zjvh0zjw!g0zjx0zknh0zko!g0zkp0zlfh0zlg!g0zlh0zm7h0zm8!g0zm90zmzh0zn0!g0zn10znrh0zns!g0znt0zojh0zok!g0zol0zpbh0zpc!g0zpd0zq3h0zq4!g0zq50zqvh0zqw!g0zqx0zrnh0zro!g0zrp0zsfh0zsg!g0zsh0zt7h0zt8!g0zt90ztzh0zu0!g0zu10zurh0zus!g0zut0zvjh0zvk!g0zvl0zwbh0zwc!g0zwd0zx3h0zx4!g0zx50zxvh0zxw!g0zxx0zynh0zyo!g0zyp0zzfh0zzg!g0zzh1007h1008!g1009100zh1010!g1011101rh101s!g101t102jh102k!g102l103bh103c!g103d1043h1044!g1045104vh104w!g104x105nh105o!g105p106fh106g!g106h1077h1078!g1079107zh1080!g1081108rh108s!g108t109jh109k!g109l10abh10ac!g10ad10b3h10b4!g10b510bvh10bw!g10bx10cnh10co!g10cp10dfh10dg!g10dh10e7h10e8!g10e910ezh10f0!g10f110frh10fs!g10ft10gjh10gk!g10gl10hbh10hc!g10hd10i3h10i4!g10i510ivh10iw!g10ix10jnh10jo!g10jp10kfh10kg!g10kh10l7h10l8!g10l910lzh10m0!g10m110mrh10ms!g10mt10njh10nk!g10nl10obh10oc!g10od10p3h10p4!g10p510pvh10pw!g10px10qnh10qo!g10qp10rfh10rg!g10rh10s7h10s8!g10s910szh10t0!g10t110trh10ts!g10tt10ujh10uk!g10ul10vbh10vc!g10vd10w3h10w4!g10w510wvh10ww!g10wx10xnh10xo!g10xp10yfh10yg!g10yh10z7h10z8!g10z910zzh1100!g1101110rh110s!g110t111jh111k!g111l112bh112c!g112d1133h1134!g1135113vh113w!g113x114nh114o!g114p115fh115g!g115h1167h1168!g1169116zh1170!g1171117rh117s!g117t118jh118k!g118l119bh119c!g119d11a3h11a4!g11a511avh11aw!g11ax11bnh11bo!g11bp11cfh11cg!g11ch11d7h11d8!g11d911dzh11e0!g11e111erh11es!g11et11fjh11fk!g11fl11gbh11gc!g11gd11h3h11h4!g11h511hvh11hw!g11hx11inh11io!g11ip11jfh11jg!g11jh11k7h11k8!g11k911kzh11l0!g11l111lrh11ls!g11lt11mjh11mk!g11ml11nbh11nc!g11nd11o3h11o4!g11o511ovh11ow!g11ox11pnh11po!g11pp11qfh11qg!g11qh11r7h11r8!g11r911rzh11s0!g11s111srh11ss!g11st11tjh11tk!g11tl11ubh11uc!g11ud11v3h11v4!g11v511vvh11vw!g11vx11wnh11wo!g11wp11xfh11xg!g11xh11y7h11y8!g11y911yzh11z0!g11z111zrh11zs!g11zt120jh120k!g120l121bh121c!g121d1223h1224!g1225122vh122w!g122x123nh123o!g123p124fh124g!g124h1257h1258!g1259125zh1260!g1261126rh126s!g126t127jh127k!g127l128bh128c!g128d1293h1294!g1295129vh129w!g129x12anh12ao!g12ap12bfh12bg!g12bh12c7h12c8!g12c912czh12d0!g12d112drh12ds!g12dt12ejh12ek!g12el12fbh12fc!g12fd12g3h12g4!g12g512gvh12gw!g12gx12hnh12ho!g12hp12ifh12ig!g12ih12j7h12j8!g12j912jzh12k0!g12k112krh12ks!g12kt12ljh12lk!g12ll12mbh12mc!g12md12n3h12n4!g12n512nvh12nw!g12nx12onh12oo!g12op12pfh12pg!g12ph12q7h12q8!g12q912qzh12r0!g12r112rrh12rs!g12rt12sjh12sk!g12sl12tbh12tc!g12td12u3h12u4!g12u512uvh12uw!g12ux12vnh12vo!g12vp12wfh12wg!g12wh12x7h12x8!g12x912xzh12y0!g12y112yrh12ys!g12yt12zjh12zk!g12zl130bh130c!g130d1313h1314!g1315131vh131w!g131x132nh132o!g132p133fh133g!g133h1347h1348!g1349134zh1350!g1351135rh135s!g135t136jh136k!g136l137bh137c!g137d1383h1384!g1385138vh138w!g138x139nh139o!g139p13afh13ag!g13ah13b7h13b8!g13b913bzh13c0!g13c113crh13cs!g13ct13djh13dk!g13dl13ebh13ec!g13ed13f3h13f4!g13f513fvh13fw!g13fx13gnh13go!g13gp13hfh13hg!g13hh13i7h13i8!g13i913izh13j0!g13j113jrh13js!g13jt13kjh13kk!g13kl13lbh13lc!g13ld13m3h13m4!g13m513mvh13mw!g13mx13nnh13no!g13np13ofh13og!g13oh13p7h13p8!g13p913pzh13q0!g13q113qrh13qs!g13qt13rjh13rk!g13rl13sbh13sc!g13sd13t3h13t4!g13t513tvh13tw!g13tx13unh13uo!g13up13vfh13vg!g13vh13w7h13w8!g13w913wzh13x0!g13x113xrh13xs!g13xt13yjh13yk!g13yl13zbh13zc!g13zd1403h1404!g1405140vh140w!g140x141nh141o!g141p142fh142g!g142h1437h1438!g1439143zh1440!g1441144rh144s!g144t145jh145k!g145l146bh146c!g146d1473h1474!g1475147vh147w!g147x148nh148o!g148p149fh149g!g149h14a7h14a8!g14a914azh14b0!g14b114brh14bs!g14bt14cjh14ck!g14cl14dbh14dc!g14dd14e3h14e4!g14e514evh14ew!g14ex14fnh14fo!g14fp14gfh14gg!g14gh14h7h14h8!g14h914hzh14i0!g14i114irh14is!g14it14jjh14jk!g14jl14kbh14kc!g14kd14l3h14l4!g14l514lvh14lw!g14lx14mnh14mo!g14mp14nfh14ng!g14nh14o7h14o8!g14o914ozh14p0!g14p114prh14ps!g14pt14qjh14qk!g14ql14rbh14rc!g14rd14s3h14s4!g14s514svh14sw!g14sx14tnh14to!g14tp14ufh14ug!g14uh14v7h14v8!g14v914vzh14w0!g14w114wrh14ws!g14wt14xjh14xk!g14xl14ybh14yc!g14yd14z3h14z4!g14z514zvh14zw!g14zx150nh150o!g150p151fh151g!g151h1527h1528!g1529152zh1530!g1531153rh153s!g153t154jh154k!g154l155bh155c!g155d1563h1564!g1565156vh156w!g156x157nh157o!g157p158fh158g!g158h1597h1598!g1599159zh15a0!g15a115arh15as!g15at15bjh15bk!g15bl15cbh15cc!g15cd15d3h15d4!g15d515dvh15dw!g15dx15enh15eo!g15ep15ffh15fg!g15fh15g7h15g8!g15g915gzh15h0!g15h115hrh15hs!g15ht15ijh15ik!g15il15jbh15jc!g15jd15k3h15k4!g15k515kvh15kw!g15kx15lnh15lo!g15lp15mfh15mg!g15mh15n7h15n8!g15n915nzh15o0!g15o115orh15os!g15ot15pjh15pk!g15pl15qbh15qc!g15qd15r3h15r4!g15r515rvh15rw!g15rx15snh15so!g15sp15tfh15tg!g15th15u7h15u8!g15u915uzh15v0!g15v115vrh15vs!g15vt15wjh15wk!g15wl15xbh15xc!g15xd15y3h15y4!g15y515yvh15yw!g15yx15znh15zo!g15zp160fh160g!g160h1617h1618!g1619161zh1620!g1621162rh162s!g162t163jh163k!g163l164bh164c!g164d1653h1654!g1655165vh165w!g165x166nh166o!g166p167fh167g!g167h1687h1688!g1689168zh1690!g1691169rh169s!g169t16ajh16ak!g16al16bbh16bc!g16bd16c3h16c4!g16c516cvh16cw!g16cx16dnh16do!g16dp16efh16eg!g16eh16f7h16f8!g16f916fzh16g0!g16g116grh16gs!g16gt16hjh16hk!g16hl16ibh16ic!g16id16j3h16j4!g16j516jvh16jw!g16jx16knh16ko!g16kp16lfh16ls16meW16mj16nvX16o01d6nI1d6o1dkve1dkw1dljI1dlp!U1dlq!A1dlr1dm0U1dm1!I1dm21dmeU1dmg1dmkU1dmm!U1dmo1dmpU1dmr1dmsU1dmu1dn3U1dn41e0tI1e0u!R1e0v!L1e1c1e63I1e64!K1e65!I1e681e6nA1e6o!N1e6p1e6qR1e6r1e6sN1e6t1e6uG1e6v!L1e6w!R1e6x!c1e741e7jA1e7k1e7oe1e7p!L1e7q!R1e7r!L1e7s!R1e7t!L1e7u!R1e7v!L1e7w!R1e7x!L1e7y!R1e7z!L1e80!R1e81!L1e82!R1e83!L1e84!R1e851e86e1e87!L1e88!R1e891e8fe1e8g!R1e8h!e1e8i!R1e8k1e8lY1e8m1e8nG1e8o!e1e8p!L1e8q!R1e8r!L1e8s!R1e8t!L1e8u!R1e8v1e92e1e94!e1e95!J1e96!K1e97!e1e9c1ed8I1edb!d1edd!G1ede1edfe1edg!J1edh!K1edi1edje1edk!L1edl!R1edm1edne1edo!R1edp!e1edq!R1edr1ee1e1ee21ee3Y1ee41ee6e1ee7!G1ee81eeye1eez!L1ef0!e1ef1!R1ef21efue1efv!L1efw!e1efx!R1efy!e1efz!L1eg01eg1R1eg2!L1eg31eg4R1eg5!Y1eg6!e1eg71eggY1egh1ehpe1ehq1ehrY1ehs1eime1eiq1eive1eiy1ej3e1ej61ejbe1eje1ejge1ejk!K1ejl!J1ejm1ejoe1ejp1ejqJ1ejs1ejyI1ek91ekbA1ekc!i1ekd1ereI1erk1ermB1err1eykI1eyl!A1f281f4gI1f4w!A1f4x1f91I1f921f96A1f9c1fa5I1fa7!B1fa81fbjI1fbk!B1fbl1fh9I1fhc1fhlQ1fhs1g7pI1g7r!B1g7s1gd7I1gdb!B1gdc1gjkI1gjl1gjnA1gjp1gjqA1gjw1gjzA1gk01gl1I1gl41gl6A1glb!A1glc1glkI1gls1glzB1gm01gpwI1gpx1gpyA1gq31gq7I1gq81gqdB1gqe!c1gqo1gs5I1gs91gsfB1gsg1h5vI1h5w1h5zA1h681h6hQ1heo1hgpI1hgr1hgsA1hgt!B1hgw1hl1I1hl21hlcA1hld1hpyI1hq81hqaA1hqb1hrrI1hrs1hs6A1hs71hs8B1hs91ht1I1ht21htbQ1htr1htuA1htv1hv3I1hv41hveA1hvf1hvhI1hvi1hvlB1hvx1hwoI1hww1hx5Q1hxc1hxeA1hxf1hyeI1hyf1hysA1hyu1hz3Q1hz41hz7B1hz8!I1hz91hzaA1hzb1i0iI1i0j!A1i0k!I1i0l!T1i0m!I1i0w1i0yA1i0z1i2aI1i2b1i2oA1i2p1i2sI1i2t1i2uB1i2v!I1i2w!B1i2x1i30A1i31!I1i321i33A1i341i3dQ1i3e!I1i3f!T1i3g!I1i3h1i3jB1i3l1i5nI1i5o1i5zA1i601i61B1i62!I1i631i64B1i65!I1i66!A1i801i94I1i95!B1i9c1iamI1ian1iayA1ib41ibdQ1ibk1ibnA1ibp1id5I1id71id8A1id9!I1ida1idgA1idj1idkA1idn1idpA1ids!I1idz!A1ie51ie9I1iea1iebA1iee1iekA1ieo1iesA1iio1ik4I1ik51ikmA1ikn1ikqI1ikr1ikuB1ikv!I1ikw1il5Q1il61il7B1il9!I1ila!A1ilb1injI1ink1io3A1io41io7I1iog1iopQ1itc1iumI1iun1iutA1iuw1iv4A1iv5!T1iv61iv7B1iv81iv9G1iva1ivcI1ivd1ivrB1ivs1ivvI1ivw1ivxA1iww1iy7I1iy81iyoA1iyp1iyqB1iyr1iysI1iz41izdQ1izk1izwT1j0g1j1mI1j1n1j1zA1j20!I1j281j2hQ1j401j57I1j5c1j5lQ1j5m1j5nI1j5o1j5qB1j5r1jcbI1jcc1jcqA1jcr1jhbI1jhc1jhlQ1jhm1jjjI1jjk1jjpA1jjr1jjsA1jjv1jjyA1jjz!I1jk0!A1jk1!I1jk21jk3A1jk41jk6B1jkg1jkpQ1jmo1jo0I1jo11jo7A1joa1jogA1joh!I1joi!T1joj!I1jok!A1jpc!I1jpd1jpmA1jpn1jqqI1jqr1jqxA1jqy!I1jqz1jr2A1jr3!T1jr4!I1jr51jr8B1jr9!T1jra!I1jrb!A1jrk!I1jrl1jrvA1jrw1jt5I1jt61jtlA1jtm1jtoB1jtp!I1jtq1jtsT1jtt1jtuB1juo1k4uI1k4v1k52A1k541k5bA1k5c!I1k5d1k5hB1k5s1k61Q1k621k6kI1k6o!T1k6p!G1k6q1k7jI1k7m1k87A1k891k8mA1kao1kc0I1kc11kc6A1kca!A1kcc1kcdA1kcf1kclA1kcm!I1kcn!A1kcw1kd5Q1kdc1kehI1kei1kemA1keo1kepA1ker1kevA1kew!I1kf41kfdQ1ko01koiI1koj1komA1kon1kv0I1kv11kv4K1kv51kvlI1kvz!B1kw01lriI1lrk1lroB1ls01oifI1oig1oiiL1oij1oilR1oim1ojlI1ojm!R1ojn1ojpI1ojq!L1ojr!R1ojs!L1ojt!R1oju1oqgI1oqh!L1oqi1oqjR1oqk1oviI1ovk1ovqS1ovr!L1ovs!R1s001sctI1scu!L1scv!R1scw1zkuI1zkw1zl5Q1zla1zlbB1zo01zotI1zow1zp0A1zp1!B1zpc1zqnI1zqo1zquA1zqv1zqxB1zqy1zr7I1zr8!B1zr9!I1zrk1zrtQ1zrv20euI20ev20ewB20ex20juI20jz!A20k0!I20k120ljA20lr20luA20lv20m7I20o020o3Y20o4!S20og20ohA20ow25fbe25fk260ve260w26dxI26f426fce2dc02djye2dlc2dleY2dlw2dlzY2dm82dx7e2fpc2ftoI2ftp2ftqA2ftr!B2fts2ftvA2jnk2jxgI2jxh2jxlA2jxm2jxoI2jxp2jyaA2jyb2jycI2jyd2jyjA2jyk2jzdI2jze2jzhA2jzi2k3lI2k3m2k3oA2k3p2l6zI2l722l8fQ2l8g2lmnI2lmo2lo6A2lo72loaI2lob2lpoA2lpp2lpwI2lpx!A2lpy2lqbI2lqc!A2lqd2lqeI2lqf2lqiB2lqj!I2lqz2lr3A2lr52lrjA2mtc2mtiA2mtk2mu0A2mu32mu9A2mub2mucA2mue2muiA2n0g2n1oI2n1s2n1yA2n1z2n25I2n282n2hQ2n2m2ne3I2ne42ne7A2ne82nehQ2nen!J2oe82ojzI2ok02ok6A2olc2on7I2on82oneA2onf!I2onk2ontQ2ony2onzL2p9t2pbfI2pbg!K2pbh2pbjI2pbk!K2pbl2prlI2pz42q67e2q682q6kI2q6l2q6ne2q6o2q98I2q992q9be2q9c2qb0I2qb12qcle2qcm2qdbj2qdc2qo4e2qo5!f2qo62qore2qos2qotI2qou2qpge2qph2qpiI2qpj2qpne2qpo!I2qpp2qpte2qpu2qpwf2qpx2qpye2qpz!f2qq02qq1e2qq22qq4f2qq52qree2qrf2qrjk2qrk2qtde2qte2qtff2qtg2qthe2qti2qtsf2qtt2qude2que2quwf2qux2quze2qv0!f2qv12qv4e2qv52qv7f2qv8!e2qv92qvbf2qvc2qvie2qvj!f2qvk!e2qvl!f2qvm2qvze2qw0!I2qw1!e2qw2!I2qw3!e2qw4!I2qw52qw9e2qwa!f2qwb2qwee2qwf!I2qwg!e2qwh2qwiI2qwj2qyne2qyo2qyuI2qyv2qzae2qzb2qzoI2qzp2r01e2r022r0pI2r0q2r1ve2r1w2r1xf2r1y2r21e2r22!f2r232r2ne2r2o!f2r2p2r2se2r2t2r2uf2r2v2r4je2r4k2r4rI2r4s2r5fe2r5g2r5lI2r5m2r7oe2r7p2r7rf2r7s2r7ue2r7v2r7zf2r802r91I2r922r94H2r952r97Y2r982r9bI2r9c2raae2rab!f2rac2rare2ras2rauf2rav2rb3e2rb4!f2rb52rbfe2rbg!f2rbh2rcve2rcw2rg3I2rg42rgfe2rgg2risI2rit2rjze2rk02rkbI2rkc2rkfe2rkg2rlzI2rm02rm7e2rm82rmhI2rmi2rmne2rmo2rnrI2rns2rnze2ro02rotI2rou2rr3e2rr42rrfI2rrg!f2rrh2rrie2rrj!f2rrk2rrre2rrs2rrzf2rs02rs5e2rs6!f2rs72rsfe2rsg2rspf2rsq2rsre2rss2rsuf2rsv2ruee2ruf!f2rug2rw4e2rw52rw6f2rw7!e2rw82rw9f2rwa!e2rwb!f2rwc2rwse2rwt2rwvf2rww!e2rwx2rx9f2rxa2ry7e2ry82s0jI2s0k2s5be2s5c2sayI2sc02sc9Q2scg2t4te2t4w47p9e47pc5m9pejny9!Ajnz4jo1rAjo5cjobzAl2ionvnhI'; + +const int singleLineBreakRangesCount = 937; + +const LineCharProperty defaultLineCharProperty = LineCharProperty.AL; diff --git a/third_party/web_unicode/lib/web_unicode/codegen/word_break_properties.dart b/third_party/web_unicode/lib/web_unicode/codegen/word_break_properties.dart new file mode 100644 index 0000000000000..594f37a5cd0c1 --- /dev/null +++ b/third_party/web_unicode/lib/web_unicode/codegen/word_break_properties.dart @@ -0,0 +1,40 @@ +// Copyright 2022 Google LLC +// +// For terms of use, see https://www.unicode.org/copyright.html + +// AUTO-GENERATED FILE. +// Generated by: tool/unicode_sync_script.dart + +// ignore_for_file: public_member_api_docs + +/// For an explanation of these enum values, see: +/// +/// * http://unicode.org/reports/tr29/#Table_Word_Break_Property_Values +enum WordCharProperty { + DoubleQuote, // serialized as "A" + SingleQuote, // serialized as "B" + HebrewLetter, // serialized as "C" + CR, // serialized as "D" + LF, // serialized as "E" + Newline, // serialized as "F" + Extend, // serialized as "G" + RegionalIndicator, // serialized as "H" + Format, // serialized as "I" + Katakana, // serialized as "J" + ALetter, // serialized as "K" + MidLetter, // serialized as "L" + MidNum, // serialized as "M" + MidNumLet, // serialized as "N" + Numeric, // serialized as "O" + ExtendNumLet, // serialized as "P" + ZWJ, // serialized as "Q" + WSegSpace, // serialized as "R" + Unknown, // serialized as "S" +} + +const String packedWordBreakProperties = + '000a!E000b000cF000d!D000w!R000y!A0013!B0018!M001a!N001c001lO001m!L001n!M001t002iK002n!P002p003eK003p!F004q!K004t!I0051!K0053!L0056!K005c005yK0060006uK006w00k7K00ke00lbK00lc00ofG00og00okK00om00onK00oq00otK00ou!M00ov!K00p2!K00p3!L00p400p6K00p8!K00pa00ptK00pv00s5K00s700w1K00w300w9G00wa010vK010x011yK01210124K0126!K0127!L0128013cK013d!M013e!K013l014tG014v!G014x014yG01500151G0153!G015c0162C0167016aC016b!K016c!L016o016tI01700171M0174017eG017g!I017k018qK018r019bG019c019lO019n!O019o!M019q019rK019s!G019t01cjK01cl!K01cm01csG01ct!I01cv01d0G01d101d2K01d301d4G01d601d9G01da01dbK01dc01dlO01dm01doK01dr!K01e7!I01e8!K01e9!G01ea01f3K01f401fuG01fx01idK01ie01ioG01ip!K01j401jdO01je01kaK01kb01kjG01kk01klK01ko!M01kq!K01kt!G01kw01lhK01li01llG01lm!K01ln01lvG01lw!K01lx01lzG01m0!K01m101m5G01mo01ncK01nd01nfG01nk01nuK01pc01pwK01py01qfK01qr01r5G01r6!I01r701s3G01s401tlK01tm01toG01tp!K01tq01u7G01u8!K01u901ufG01ug01upK01uq01urG01uu01v3O01v501vkK01vl01vnG01vp01vwK01vz01w0K01w301woK01wq01wwK01wy!K01x201x5K01x8!G01x9!K01xa01xgG01xj01xkG01xn01xpG01xq!K01xz!G01y401y5K01y701y9K01ya01ybG01ye01ynO01yo01ypK01z0!K01z2!G01z501z7G01z901zeK01zj01zkK01zn0208K020a020gK020i020jK020l020mK020o020pK020s!G020u020yG02130214G02170219G021d!G021l021oK021q!K021y0227O02280229G022a022cK022d!G022p022rG022t0231K02330235K0237023sK023u0240K02420243K02450249K024c!G024d!K024e024lG024n024pG024r024tG024w!K025c025dK025e025fG025i025rO0261!K02620267G0269026bG026d026kK026n026oK026r027cK027e027kK027m027nK027p027tK027w!G027x!K027y0284G02870288G028b028dG028l028nG028s028tK028v028xK028y028zG0292029bO029d!K029u!G029v!K029x02a2K02a602a8K02aa02adK02ah02aiK02ak!K02am02anK02ar02asK02aw02ayK02b202bdK02bi02bmG02bq02bsG02bu02bxG02c0!K02c7!G02cm02cvO02dc02dgG02dh02doK02dq02dsK02du02egK02ei02exK02f1!K02f202f8G02fa02fcG02fe02fhG02fp02fqG02fs02fuK02g002g1K02g202g3G02g602gfO02gw!K02gx02gzG02h102h8K02ha02hcK02he02i0K02i202ibK02id02ihK02ik!G02il!K02im02isG02iu02iwG02iy02j1G02j902jaG02ji!K02jk02jlK02jm02jnG02jq02jzO02k102k2K02kg02kjG02kk02ksK02ku02kwK02ky02m2K02m302m4G02m5!K02m602mcG02me02mgG02mi02mlG02mm!K02ms02muK02mv!G02n302n5K02n602n7G02na02njO02nu02nzK02o102o3G02o502omK02oq02pdK02pf02pnK02pp!K02ps02pyK02q2!G02q702qcG02qe!G02qg02qnG02qu02r3O02r602r7G02sx!G02t002t6G02tj02tqG02ts02u1O02wh!G02wk02wsG02x402x9G02xc02xlO02yo!K02zc02zdG02zk02ztO0305!G0307!G0309!G030e030fG030g030nK030p031oK031t032cG032e032fG032g032kK032l032vG032x033wG0346!G036z037iG037k037tO03860389G038e038gG038i038kG038n038tG038x0390G039e039pG039r!G039s03a1O03a203a5G03a803b9K03bb!K03bh!K03bk03cqK03cs03m0K03m203m5K03m803meK03mg!K03mi03mlK03mo03nsK03nu03nxK03o003owK03oy03p1K03p403paK03pc!K03pe03phK03pk03pyK03q003rkK03rm03rpK03rs03tmK03tp03trG03uo03v3K03vk03xxK03y003y5K03y904fgK04fj04fzK04g0!R04g104gqK04gw04iyK04j204jcK04jk04jwK04jy04k1K04k204k4G04kg04kxK04ky04l0G04lc04ltK04lu04lvG04m804mkK04mm04moK04mq04mrG04ok04pfG04pp!G04ps04q1O04qz04r1G04r2!I04r404rdO04rk04u0K04u804ucK04ud04ueG04uf04vcK04vd!G04ve!K04vk04xhK04xs04ymK04yo04yzG04z404zfG04zq04zzO053k053tO054w055iK055j055nG0579057iG057k058cG058f!G058g058pO058w0595O059s05a8G05c005c4G05c505dfK05dg05dwG05dx05e3K05e805ehO05ez05f7G05fk05fmG05fn05ggK05gh05gtG05gu05gvK05gw05h5O05h605idK05ie05irG05j405k3K05k405knG05kw05l5O05l905lbK05lc05llO05lm05mlK05mo05mwK05n405oaK05od05ofK05ow05oyG05p005pkG05pl05poK05pp!G05pq05pvK05pw!G05px05pyK05pz05q1G05q2!K05q805vjK05vk05x5G05x705xbG05xc0651K06540659K065c066dK066g066lK066o066vK066x!K066z!K0671!K0673067xK0680069gK069i069oK069q!K069u069wK069y06a4K06a806abK06ae06ajK06ao06b0K06b606b8K06ba06bgK06bk06bqR06bs06buR06bw!G06bx!Q06by06bzI06c806c9N06ck!N06cn!L06co06cpF06cq06cuI06cv!P06db06dcP06dg!M06dw!P06e7!R06e806ecI06ee06enI06ep!K06f3!K06fk06fwK06hc06i8G06iq!K06iv!K06iy06j7K06j9!K06jd06jhK06jo!K06jq!K06js!K06ju06jxK06jz06k9K06kc06kfK06kl06kpK06ku!K06lc06mgK079207ahK08ow08q6K08q808riK08rk08v8K08vf08viK08vj08vlG08vm08vnK08w008x1K08x3!K08x9!K08xc08yvK08z3!K08zj!G08zk0906K090g090mK090o090uK090w0912K0914091aK091c091iK091k091qK091s091yK09200926K09280933G094f!K09hc!R09hh!K09ii09inG09ip09itJ09iz09j0K09ll09lmG09ln09loJ09ls09oaJ09oc09ofJ09ol09prK09pt09seK09sw09trK09v409vjJ0a1c0a2mJ0a2o0a53J0vls0wi4K0wk00wl9K0wlc0wssK0wsw0wtbK0wtc0wtlO0wtm0wtnK0wu80wviK0wvj0wvmG0wvo0wvxG0wvz0wwtK0wwu0wwvG0www0wz3K0wz40wz5G0wzs0x4vK0x4y0x56K0x6d0x6pK0x6q!G0x6r0x6tK0x6u!G0x6v0x6yK0x6z!G0x700x7mK0x7n0x7rG0x7w!G0x8g0x9vK0xa80xa9G0xaa0xbnK0xbo0xc5G0xcg0xcpO0xcw0xddG0xde0xdjK0xdn!K0xdp0xdqK0xdr!G0xds0xe1O0xe20xetK0xeu0xf1G0xf40xfqK0xfr0xg3G0xgg0xh8K0xhc0xhfG0xhg0xiqK0xir0xj4G0xjj!K0xjk0xjtO0xk5!G0xkg0xkpO0xkw0xm0K0xm10xmeG0xmo0xmqK0xmr!G0xms0xmzK0xn00xn1G0xn40xndO0xob0xodG0xps!G0xpu0xpwG0xpz0xq0G0xq60xq7G0xq9!G0xr40xreK0xrf0xrjG0xrm0xroK0xrp0xrqG0xs10xs6K0xs90xseK0xsh0xsmK0xsw0xt2K0xt40xtaK0xtc0xuxK0xv40xyaK0xyb0xyiG0xyk0xylG0xyo0xyxO0xz416lfK16ls16meK16mj16nvK1dkw1dl2K1dlf1dljK1dlp!C1dlq!G1dlr1dm0C1dm21dmeC1dmg1dmkC1dmm!C1dmo1dmpC1dmr1dmsC1dmu1dn3C1dn41dptK1dqr1e0tK1e1c1e33K1e361e4nK1e5s1e63K1e681e6nG1e6o!M1e6r!L1e6s!M1e741e7jG1e7n1e7oP1e8d1e8fP1e8g!M1e8i!N1e8k!M1e8l!L1e9c1e9gK1e9i1ed8K1edb!I1edj!N1edo!M1edq!N1eds1ee1O1ee2!L1ee3!M1ee91eeyK1ef3!P1ef51efuK1eg61ehpJ1ehq1ehrG1ehs1eimK1eiq1eivK1eiy1ej3K1ej61ejbK1eje1ejgK1ek91ekbI1ekg1ekrK1ekt1eliK1elk1em2K1em41em5K1em71emlK1emo1en1K1eo01ereK1etc1eusK1eyl!G1f281f30K1f341f4gK1f4w!G1f5s1f6nK1f711f7uK1f801f91K1f921f96G1f9c1fa5K1fa81fb7K1fbc1fbjK1fbl1fbpK1fcw1fh9K1fhc1fhlO1fhs1firK1fiw1fjvK1fk01fl3K1flc1fmrK1fr41fzqK1g001g0lK1g0w1g13K1g5c1g5hK1g5k!K1g5m1g6tK1g6v1g6wK1g70!K1g731g7pK1g801g8mK1g8w1g9qK1gbk1gc2K1gc41gc5K1gcg1gd1K1gdc1ge1K1gg01ghjK1ghq1ghrK1gjk!K1gjl1gjnG1gjp1gjqG1gjw1gjzG1gk01gk3K1gk51gk7K1gk91gl1K1gl41gl6G1glb!G1gm81gn0K1gn41gnwK1gow1gp3K1gp51gpwK1gpx1gpyG1gqo1gs5K1gsg1gt1K1gtc1gtuK1gu81gupK1gxs1gzsK1h1c1h2qK1h341h4iK1h4w1h5vK1h5w1h5zG1h681h6hO1hfk1hgpK1hgr1hgsG1hgw1hgxK1hj41hjwK1hk7!K1hkg1hl1K1hl21hlcG1ho01hokK1hpc1hpyK1hq81hqaG1hqb1hrrK1hrs1hs6G1ht21htbO1htr1htuG1htv1hv3K1hv41hveG1hvh!I1hvx!I1hw01hwoK1hww1hx5O1hxc1hxeG1hxf1hyeK1hyf1hysG1hyu1hz3O1hz8!K1hz91hzaG1hzb!K1hzk1i0iK1i0j!G1i0m!K1i0w1i0yG1i0z1i2aK1i2b1i2oG1i2p1i2sK1i2x1i30G1i321i33G1i341i3dO1i3e!K1i3g!K1i4g1i4xK1i4z1i5nK1i5o1i5zG1i66!G1i801i86K1i88!K1i8a1i8dK1i8f1i8tK1i8v1i94K1i9c1iamK1ian1iayG1ib41ibdO1ibk1ibnG1ibp1ibwK1ibz1ic0K1ic31icoK1icq1icwK1icy1iczK1id11id5K1id71id8G1id9!K1ida1idgG1idj1idkG1idn1idpG1ids!K1idz!G1ie51ie9K1iea1iebG1iee1iekG1ieo1iesG1iio1ik4K1ik51ikmG1ikn1ikqK1ikw1il5O1ila!G1ilb1ildK1im81injK1ink1io3G1io41io5K1io7!K1iog1iopO1itc1iumK1iun1iutG1iuw1iv4G1ivs1ivvK1ivw1ivxG1iww1iy7K1iy81iyoG1iys!K1iz41izdO1j0g1j1mK1j1n1j1zG1j20!K1j281j2hO1j4t1j57G1j5c1j5lO1jb41jcbK1jcc1jcqG1jfk1jhbK1jhc1jhlO1ji71jieK1jih!K1jik1jirK1jit1jiuK1jiw1jjjK1jjk1jjpG1jjr1jjsG1jjv1jjyG1jjz!K1jk0!G1jk1!K1jk21jk3G1jkg1jkpO1jmo1jmvK1jmy1jo0K1jo11jo7G1joa1jogG1joh!K1joj!K1jok!G1jpc!K1jpd1jpmG1jpn1jqqK1jqr1jqxG1jqy!K1jqz1jr2G1jrb!G1jrk!K1jrl1jrvG1jrw1jt5K1jt61jtlG1jtp!K1juo1jw8K1k3k1k3sK1k3u1k4uK1k4v1k52G1k541k5bG1k5c!K1k5s1k61O1k6q1k7jK1k7m1k87G1k891k8mG1kao1kauK1kaw1kaxK1kaz1kc0K1kc11kc6G1kca!G1kcc1kcdG1kcf1kclG1kcm!K1kcn!G1kcw1kd5O1kdc1kdhK1kdj1kdkK1kdm1kehK1kei1kemG1keo1kepG1ker1kevG1kew!K1kf41kfdO1ko01koiK1koj1komG1kts!K1kw01lllK1log1lriK1ls01lxfK1o1s1oviK1ovk1ovsI1s001sg6K1z401zjsK1zk01zkuK1zkw1zl5O1zo01zotK1zow1zp0G1zpc1zqnK1zqo1zquG1zr41zr7K1zrk1zrtO1zs31zsnK1zst1ztbK20cg20e7K20hs20juK20jz!G20k0!K20k120ljG20lr20luG20lv20m7K20o020o1K20o3!K20o4!G20og20ohG2dc0!J2dlw2dlzJ2fpc2fsaK2fsg2fssK2fsw2ft4K2ftc2ftlK2ftp2ftqG2fts2ftvI2jxh2jxlG2jxp2jxuG2jxv2jy2I2jy32jyaG2jyd2jyjG2jze2jzhG2k3m2k3oG2kg02kicK2kie2kkcK2kke2kkfK2kki!K2kkl2kkmK2kkp2kksK2kku2kl5K2kl7!K2kl92klfK2klh2kn9K2knb2kneK2knh2knoK2knq2knwK2kny2kopK2kor2kouK2kow2kp0K2kp2!K2kp62kpcK2kpe2kytK2kyw2kzkK2kzm2l0aK2l0c2l16K2l182l1wK2l1y2l2sK2l2u2l3iK2l3k2l4eK2l4g2l54K2l562l60K2l622l6qK2l6s2l6zK2l722l8fO2lmo2lo6G2lob2lpoG2lpx!G2lqc!G2lqz2lr3G2lr52lrjG2mtc2mtiG2mtk2mu0G2mu32mu9G2mub2mucG2mue2muiG2n0g2n1oK2n1s2n1yG2n1z2n25K2n282n2hO2n2m!K2ncw2ne3K2ne42ne7G2ne82nehO2oe82ojoK2ok02ok6G2olc2on7K2on82oneG2onf!K2onk2ontO2pkw2pkzK2pl12plrK2plt2pluK2plw!K2plz!K2pm12pmaK2pmc2pmfK2pmh!K2pmj!K2pmq!K2pmv!K2pmx!K2pmz!K2pn12pn3K2pn52pn6K2pn8!K2pnb!K2pnd!K2pnf!K2pnh!K2pnj!K2pnl2pnmK2pno!K2pnr2pnuK2pnw2po2K2po42po7K2po92pocK2poe!K2pog2popK2por2pp7K2ppd2ppfK2pph2pplK2ppn2pq3K2q7k2q89K2q8g2q95K2q9c2qa1K2qcm2qdbH2qrf2qrjG2sc02sc9Ojny9!Ijnz4jo1rGjo5cjobzG'; + +const int singleWordBreakRangesCount = 231; + +const WordCharProperty defaultWordCharProperty = WordCharProperty.Unknown; diff --git a/third_party/web_unicode/properties/LineBreak.txt b/third_party/web_unicode/properties/LineBreak.txt new file mode 100644 index 0000000000000..22abddcd90e02 --- /dev/null +++ b/third_party/web_unicode/properties/LineBreak.txt @@ -0,0 +1,3487 @@ +# LineBreak-13.0.0.txt +# Date: 2020-02-17, 07:43:02 GMT [KW, LI] +# © 2020 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Line_Break Property +# +# This file is a normative contributory data file in the +# Unicode Character Database. +# +# The format is two fields separated by a semicolon. +# Field 0: Unicode code point value or range of code point values +# Field 1: Line_Break property, consisting of one of the following values: +# Non-tailorable: +# "BK", "CM", "CR", "GL", "LF", "NL", "SP", "WJ", "ZW", "ZWJ" +# Tailorable: +# "AI", "AL", "B2", "BA", "BB", "CB", "CJ", "CL", "CP", "EB", +# "EM", "EX", "H2", "H3", "HL", "HY", "ID", "IN", "IS", "JL", +# "JT", "JV", "NS", "NU", "OP", "PO", "PR", "QU", "RI", "SA", +# "SG", "SY", "XX" +# - All code points, assigned and unassigned, that are not listed +# explicitly are given the value "XX". +# - The unassigned code points in the following blocks default to "ID": +# CJK Unified Ideographs Extension A: U+3400..U+4DBF +# CJK Unified Ideographs: U+4E00..U+9FFF +# CJK Compatibility Ideographs: U+F900..U+FAFF +# - All undesignated code points in Planes 2 and 3, whether inside or +# outside of allocated blocks, default to "ID": +# Plane 2: U+20000..U+2FFFD +# Plane 3: U+30000..U+3FFFD +# - All unassigned code points in the following Plane 1 ranges, whether +# inside or outside of allocated blocks, also default to "ID": +# Plane 1 range: U+1F000..U+1FAFF +# Plane 1 range: U+1FC00..U+1FFFD +# - The unassigned code points in the following block default to "PR": +# Currency Symbols: U+20A0..U+20CF +# +# Character ranges are specified as for other property files in the +# Unicode Character Database. +# +# For legacy reasons, there are no spaces before or after the semicolon +# which separates the two fields. The comments following the number sign +# "#" list the General_Category property value or the L& alias of the +# derived value LC, the Unicode character name or names, and, in lines +# with ranges of code points, the code point count in square brackets. +# +# For more information, see UAX #14: Unicode Line Breaking Algorithm, +# at http://www.unicode.org/reports/tr14/ +# +# @missing: 0000..10FFFF; XX +0000..0008;CM # Cc [9] .. +0009;BA # Cc +000A;LF # Cc +000B..000C;BK # Cc [2] .. +000D;CR # Cc +000E..001F;CM # Cc [18] .. +0020;SP # Zs SPACE +0021;EX # Po EXCLAMATION MARK +0022;QU # Po QUOTATION MARK +0023;AL # Po NUMBER SIGN +0024;PR # Sc DOLLAR SIGN +0025;PO # Po PERCENT SIGN +0026;AL # Po AMPERSAND +0027;QU # Po APOSTROPHE +0028;OP # Ps LEFT PARENTHESIS +0029;CP # Pe RIGHT PARENTHESIS +002A;AL # Po ASTERISK +002B;PR # Sm PLUS SIGN +002C;IS # Po COMMA +002D;HY # Pd HYPHEN-MINUS +002E;IS # Po FULL STOP +002F;SY # Po SOLIDUS +0030..0039;NU # Nd [10] DIGIT ZERO..DIGIT NINE +003A..003B;IS # Po [2] COLON..SEMICOLON +003C..003E;AL # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN +003F;EX # Po QUESTION MARK +0040;AL # Po COMMERCIAL AT +0041..005A;AL # Lu [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z +005B;OP # Ps LEFT SQUARE BRACKET +005C;PR # Po REVERSE SOLIDUS +005D;CP # Pe RIGHT SQUARE BRACKET +005E;AL # Sk CIRCUMFLEX ACCENT +005F;AL # Pc LOW LINE +0060;AL # Sk GRAVE ACCENT +0061..007A;AL # Ll [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z +007B;OP # Ps LEFT CURLY BRACKET +007C;BA # Sm VERTICAL LINE +007D;CL # Pe RIGHT CURLY BRACKET +007E;AL # Sm TILDE +007F;CM # Cc +0080..0084;CM # Cc [5] .. +0085;NL # Cc +0086..009F;CM # Cc [26] .. +00A0;GL # Zs NO-BREAK SPACE +00A1;OP # Po INVERTED EXCLAMATION MARK +00A2;PO # Sc CENT SIGN +00A3..00A5;PR # Sc [3] POUND SIGN..YEN SIGN +00A6;AL # So BROKEN BAR +00A7;AI # Po SECTION SIGN +00A8;AI # Sk DIAERESIS +00A9;AL # So COPYRIGHT SIGN +00AA;AI # Lo FEMININE ORDINAL INDICATOR +00AB;QU # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00AC;AL # Sm NOT SIGN +00AD;BA # Cf SOFT HYPHEN +00AE;AL # So REGISTERED SIGN +00AF;AL # Sk MACRON +00B0;PO # So DEGREE SIGN +00B1;PR # Sm PLUS-MINUS SIGN +00B2..00B3;AI # No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE +00B4;BB # Sk ACUTE ACCENT +00B5;AL # Ll MICRO SIGN +00B6..00B7;AI # Po [2] PILCROW SIGN..MIDDLE DOT +00B8;AI # Sk CEDILLA +00B9;AI # No SUPERSCRIPT ONE +00BA;AI # Lo MASCULINE ORDINAL INDICATOR +00BB;QU # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +00BC..00BE;AI # No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS +00BF;OP # Po INVERTED QUESTION MARK +00C0..00D6;AL # Lu [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS +00D7;AI # Sm MULTIPLICATION SIGN +00D8..00F6;AL # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS +00F7;AI # Sm DIVISION SIGN +00F8..00FF;AL # Ll [8] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER Y WITH DIAERESIS +0100..017F;AL # L& [128] LATIN CAPITAL LETTER A WITH MACRON..LATIN SMALL LETTER LONG S +0180..01BA;AL # L& [59] LATIN SMALL LETTER B WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL +01BB;AL # Lo LATIN LETTER TWO WITH STROKE +01BC..01BF;AL # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN +01C0..01C3;AL # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK +01C4..024F;AL # L& [140] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER Y WITH STROKE +0250..0293;AL # Ll [68] LATIN SMALL LETTER TURNED A..LATIN SMALL LETTER EZH WITH CURL +0294;AL # Lo LATIN LETTER GLOTTAL STOP +0295..02AF;AL # Ll [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +02B0..02C1;AL # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP +02C2..02C5;AL # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD +02C6;AL # Lm MODIFIER LETTER CIRCUMFLEX ACCENT +02C7;AI # Lm CARON +02C8;BB # Lm MODIFIER LETTER VERTICAL LINE +02C9..02CB;AI # Lm [3] MODIFIER LETTER MACRON..MODIFIER LETTER GRAVE ACCENT +02CC;BB # Lm MODIFIER LETTER LOW VERTICAL LINE +02CD;AI # Lm MODIFIER LETTER LOW MACRON +02CE..02CF;AL # Lm [2] MODIFIER LETTER LOW GRAVE ACCENT..MODIFIER LETTER LOW ACUTE ACCENT +02D0;AI # Lm MODIFIER LETTER TRIANGULAR COLON +02D1;AL # Lm MODIFIER LETTER HALF TRIANGULAR COLON +02D2..02D7;AL # Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN +02D8..02DB;AI # Sk [4] BREVE..OGONEK +02DC;AL # Sk SMALL TILDE +02DD;AI # Sk DOUBLE ACUTE ACCENT +02DE;AL # Sk MODIFIER LETTER RHOTIC HOOK +02DF;BB # Sk MODIFIER LETTER CROSS ACCENT +02E0..02E4;AL # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +02E5..02EB;AL # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK +02EC;AL # Lm MODIFIER LETTER VOICING +02ED;AL # Sk MODIFIER LETTER UNASPIRATED +02EE;AL # Lm MODIFIER LETTER DOUBLE APOSTROPHE +02EF..02FF;AL # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW +0300..034E;CM # Mn [79] COMBINING GRAVE ACCENT..COMBINING UPWARDS ARROW BELOW +034F;GL # Mn COMBINING GRAPHEME JOINER +0350..035B;CM # Mn [12] COMBINING RIGHT ARROWHEAD ABOVE..COMBINING ZIGZAG ABOVE +035C..0362;GL # Mn [7] COMBINING DOUBLE BREVE BELOW..COMBINING DOUBLE RIGHTWARDS ARROW BELOW +0363..036F;CM # Mn [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X +0370..0373;AL # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI +0374;AL # Lm GREEK NUMERAL SIGN +0375;AL # Sk GREEK LOWER NUMERAL SIGN +0376..0377;AL # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA +037A;AL # Lm GREEK YPOGEGRAMMENI +037B..037D;AL # Ll [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL +037E;IS # Po GREEK QUESTION MARK +037F;AL # Lu GREEK CAPITAL LETTER YOT +0384..0385;AL # Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS +0386;AL # Lu GREEK CAPITAL LETTER ALPHA WITH TONOS +0387;AL # Po GREEK ANO TELEIA +0388..038A;AL # Lu [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS +038C;AL # Lu GREEK CAPITAL LETTER OMICRON WITH TONOS +038E..03A1;AL # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO +03A3..03F5;AL # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL +03F6;AL # Sm GREEK REVERSED LUNATE EPSILON SYMBOL +03F7..03FF;AL # L& [9] GREEK CAPITAL LETTER SHO..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL +0400..0481;AL # L& [130] CYRILLIC CAPITAL LETTER IE WITH GRAVE..CYRILLIC SMALL LETTER KOPPA +0482;AL # So CYRILLIC THOUSANDS SIGN +0483..0487;CM # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE +0488..0489;CM # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN +048A..04FF;AL # L& [118] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER HA WITH STROKE +0500..052F;AL # L& [48] CYRILLIC CAPITAL LETTER KOMI DE..CYRILLIC SMALL LETTER EL WITH DESCENDER +0531..0556;AL # Lu [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH +0559;AL # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING +055A..055F;AL # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK +0560..0588;AL # Ll [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE +0589;IS # Po ARMENIAN FULL STOP +058A;BA # Pd ARMENIAN HYPHEN +058D..058E;AL # So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN +058F;PR # Sc ARMENIAN DRAM SIGN +0591..05BD;CM # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG +05BE;BA # Pd HEBREW PUNCTUATION MAQAF +05BF;CM # Mn HEBREW POINT RAFE +05C0;AL # Po HEBREW PUNCTUATION PASEQ +05C1..05C2;CM # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C3;AL # Po HEBREW PUNCTUATION SOF PASUQ +05C4..05C5;CM # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT +05C6;EX # Po HEBREW PUNCTUATION NUN HAFUKHA +05C7;CM # Mn HEBREW POINT QAMATS QATAN +05D0..05EA;HL # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV +05EF..05F2;HL # Lo [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD +05F3..05F4;AL # Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM +0600..0605;AL # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE +0606..0608;AL # Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY +0609..060A;PO # Po [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN +060B;PO # Sc AFGHANI SIGN +060C..060D;IS # Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR +060E..060F;AL # So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA +0610..061A;CM # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA +061B;EX # Po ARABIC SEMICOLON +061C;CM # Cf ARABIC LETTER MARK +061E..061F;EX # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK +0620..063F;AL # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE +0640;AL # Lm ARABIC TATWEEL +0641..064A;AL # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH +064B..065F;CM # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW +0660..0669;NU # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE +066A;PO # Po ARABIC PERCENT SIGN +066B..066C;NU # Po [2] ARABIC DECIMAL SEPARATOR..ARABIC THOUSANDS SEPARATOR +066D;AL # Po ARABIC FIVE POINTED STAR +066E..066F;AL # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF +0670;CM # Mn ARABIC LETTER SUPERSCRIPT ALEF +0671..06D3;AL # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +06D4;EX # Po ARABIC FULL STOP +06D5;AL # Lo ARABIC LETTER AE +06D6..06DC;CM # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN +06DD;AL # Cf ARABIC END OF AYAH +06DE;AL # So ARABIC START OF RUB EL HIZB +06DF..06E4;CM # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA +06E5..06E6;AL # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH +06E7..06E8;CM # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON +06E9;AL # So ARABIC PLACE OF SAJDAH +06EA..06ED;CM # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM +06EE..06EF;AL # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V +06F0..06F9;NU # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE +06FA..06FC;AL # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW +06FD..06FE;AL # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN +06FF;AL # Lo ARABIC LETTER HEH WITH INVERTED V +0700..070D;AL # Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS +070F;AL # Cf SYRIAC ABBREVIATION MARK +0710;AL # Lo SYRIAC LETTER ALAPH +0711;CM # Mn SYRIAC LETTER SUPERSCRIPT ALAPH +0712..072F;AL # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH +0730..074A;CM # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH +074D..074F;AL # Lo [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE +0750..077F;AL # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE +0780..07A5;AL # Lo [38] THAANA LETTER HAA..THAANA LETTER WAAVU +07A6..07B0;CM # Mn [11] THAANA ABAFILI..THAANA SUKUN +07B1;AL # Lo THAANA LETTER NAA +07C0..07C9;NU # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE +07CA..07EA;AL # Lo [33] NKO LETTER A..NKO LETTER JONA RA +07EB..07F3;CM # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE +07F4..07F5;AL # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE +07F6;AL # So NKO SYMBOL OO DENNEN +07F7;AL # Po NKO SYMBOL GBAKURUNEN +07F8;IS # Po NKO COMMA +07F9;EX # Po NKO EXCLAMATION MARK +07FA;AL # Lm NKO LAJANYALAN +07FD;CM # Mn NKO DANTAYALAN +07FE..07FF;PR # Sc [2] NKO DOROME SIGN..NKO TAMAN SIGN +0800..0815;AL # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF +0816..0819;CM # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH +081A;AL # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT +081B..0823;CM # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A +0824;AL # Lm SAMARITAN MODIFIER LETTER SHORT A +0825..0827;CM # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U +0828;AL # Lm SAMARITAN MODIFIER LETTER I +0829..082D;CM # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA +0830..083E;AL # Po [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU +0840..0858;AL # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN +0859..085B;CM # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +085E;AL # Po MANDAIC PUNCTUATION +0860..086A;AL # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA +08A0..08B4;AL # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B6..08C7;AL # Lo [18] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE +08D3..08E1;CM # Mn [15] ARABIC SMALL LOW WAW..ARABIC SMALL HIGH SIGN SAFHA +08E2;AL # Cf ARABIC DISPUTED END OF AYAH +08E3..08FF;CM # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA +0900..0902;CM # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA +0903;CM # Mc DEVANAGARI SIGN VISARGA +0904..0939;AL # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA +093A;CM # Mn DEVANAGARI VOWEL SIGN OE +093B;CM # Mc DEVANAGARI VOWEL SIGN OOE +093C;CM # Mn DEVANAGARI SIGN NUKTA +093D;AL # Lo DEVANAGARI SIGN AVAGRAHA +093E..0940;CM # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II +0941..0948;CM # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI +0949..094C;CM # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU +094D;CM # Mn DEVANAGARI SIGN VIRAMA +094E..094F;CM # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW +0950;AL # Lo DEVANAGARI OM +0951..0957;CM # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE +0958..0961;AL # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL +0962..0963;CM # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL +0964..0965;BA # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA +0966..096F;NU # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE +0970;AL # Po DEVANAGARI ABBREVIATION SIGN +0971;AL # Lm DEVANAGARI SIGN HIGH SPACING DOT +0972..097F;AL # Lo [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA +0980;AL # Lo BENGALI ANJI +0981;CM # Mn BENGALI SIGN CANDRABINDU +0982..0983;CM # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA +0985..098C;AL # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L +098F..0990;AL # Lo [2] BENGALI LETTER E..BENGALI LETTER AI +0993..09A8;AL # Lo [22] BENGALI LETTER O..BENGALI LETTER NA +09AA..09B0;AL # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA +09B2;AL # Lo BENGALI LETTER LA +09B6..09B9;AL # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA +09BC;CM # Mn BENGALI SIGN NUKTA +09BD;AL # Lo BENGALI SIGN AVAGRAHA +09BE..09C0;CM # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II +09C1..09C4;CM # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR +09C7..09C8;CM # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI +09CB..09CC;CM # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU +09CD;CM # Mn BENGALI SIGN VIRAMA +09CE;AL # Lo BENGALI LETTER KHANDA TA +09D7;CM # Mc BENGALI AU LENGTH MARK +09DC..09DD;AL # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA +09DF..09E1;AL # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL +09E2..09E3;CM # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL +09E6..09EF;NU # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE +09F0..09F1;AL # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL +09F2..09F3;PO # Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN +09F4..09F8;AL # No [5] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR +09F9;PO # No BENGALI CURRENCY DENOMINATOR SIXTEEN +09FA;AL # So BENGALI ISSHAR +09FB;PR # Sc BENGALI GANDA MARK +09FC;AL # Lo BENGALI LETTER VEDIC ANUSVARA +09FD;AL # Po BENGALI ABBREVIATION SIGN +09FE;CM # Mn BENGALI SANDHI MARK +0A01..0A02;CM # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI +0A03;CM # Mc GURMUKHI SIGN VISARGA +0A05..0A0A;AL # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU +0A0F..0A10;AL # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI +0A13..0A28;AL # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA +0A2A..0A30;AL # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA +0A32..0A33;AL # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA +0A35..0A36;AL # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA +0A38..0A39;AL # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA +0A3C;CM # Mn GURMUKHI SIGN NUKTA +0A3E..0A40;CM # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II +0A41..0A42;CM # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU +0A47..0A48;CM # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI +0A4B..0A4D;CM # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA +0A51;CM # Mn GURMUKHI SIGN UDAAT +0A59..0A5C;AL # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA +0A5E;AL # Lo GURMUKHI LETTER FA +0A66..0A6F;NU # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE +0A70..0A71;CM # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK +0A72..0A74;AL # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR +0A75;CM # Mn GURMUKHI SIGN YAKASH +0A76;AL # Po GURMUKHI ABBREVIATION SIGN +0A81..0A82;CM # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA +0A83;CM # Mc GUJARATI SIGN VISARGA +0A85..0A8D;AL # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E +0A8F..0A91;AL # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O +0A93..0AA8;AL # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA +0AAA..0AB0;AL # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA +0AB2..0AB3;AL # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA +0AB5..0AB9;AL # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA +0ABC;CM # Mn GUJARATI SIGN NUKTA +0ABD;AL # Lo GUJARATI SIGN AVAGRAHA +0ABE..0AC0;CM # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II +0AC1..0AC5;CM # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E +0AC7..0AC8;CM # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI +0AC9;CM # Mc GUJARATI VOWEL SIGN CANDRA O +0ACB..0ACC;CM # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU +0ACD;CM # Mn GUJARATI SIGN VIRAMA +0AD0;AL # Lo GUJARATI OM +0AE0..0AE1;AL # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL +0AE2..0AE3;CM # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AE6..0AEF;NU # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE +0AF0;AL # Po GUJARATI ABBREVIATION SIGN +0AF1;PR # Sc GUJARATI RUPEE SIGN +0AF9;AL # Lo GUJARATI LETTER ZHA +0AFA..0AFF;CM # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE +0B01;CM # Mn ORIYA SIGN CANDRABINDU +0B02..0B03;CM # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA +0B05..0B0C;AL # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L +0B0F..0B10;AL # Lo [2] ORIYA LETTER E..ORIYA LETTER AI +0B13..0B28;AL # Lo [22] ORIYA LETTER O..ORIYA LETTER NA +0B2A..0B30;AL # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA +0B32..0B33;AL # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA +0B35..0B39;AL # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA +0B3C;CM # Mn ORIYA SIGN NUKTA +0B3D;AL # Lo ORIYA SIGN AVAGRAHA +0B3E;CM # Mc ORIYA VOWEL SIGN AA +0B3F;CM # Mn ORIYA VOWEL SIGN I +0B40;CM # Mc ORIYA VOWEL SIGN II +0B41..0B44;CM # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR +0B47..0B48;CM # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI +0B4B..0B4C;CM # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU +0B4D;CM # Mn ORIYA SIGN VIRAMA +0B55..0B56;CM # Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK +0B57;CM # Mc ORIYA AU LENGTH MARK +0B5C..0B5D;AL # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA +0B5F..0B61;AL # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL +0B62..0B63;CM # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL +0B66..0B6F;NU # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE +0B70;AL # So ORIYA ISSHAR +0B71;AL # Lo ORIYA LETTER WA +0B72..0B77;AL # No [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS +0B82;CM # Mn TAMIL SIGN ANUSVARA +0B83;AL # Lo TAMIL SIGN VISARGA +0B85..0B8A;AL # Lo [6] TAMIL LETTER A..TAMIL LETTER UU +0B8E..0B90;AL # Lo [3] TAMIL LETTER E..TAMIL LETTER AI +0B92..0B95;AL # Lo [4] TAMIL LETTER O..TAMIL LETTER KA +0B99..0B9A;AL # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA +0B9C;AL # Lo TAMIL LETTER JA +0B9E..0B9F;AL # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA +0BA3..0BA4;AL # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA +0BA8..0BAA;AL # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA +0BAE..0BB9;AL # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA +0BBE..0BBF;CM # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I +0BC0;CM # Mn TAMIL VOWEL SIGN II +0BC1..0BC2;CM # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU +0BC6..0BC8;CM # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI +0BCA..0BCC;CM # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU +0BCD;CM # Mn TAMIL SIGN VIRAMA +0BD0;AL # Lo TAMIL OM +0BD7;CM # Mc TAMIL AU LENGTH MARK +0BE6..0BEF;NU # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE +0BF0..0BF2;AL # No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND +0BF3..0BF8;AL # So [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN +0BF9;PR # Sc TAMIL RUPEE SIGN +0BFA;AL # So TAMIL NUMBER SIGN +0C00;CM # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE +0C01..0C03;CM # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C04;CM # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE +0C05..0C0C;AL # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L +0C0E..0C10;AL # Lo [3] TELUGU LETTER E..TELUGU LETTER AI +0C12..0C28;AL # Lo [23] TELUGU LETTER O..TELUGU LETTER NA +0C2A..0C39;AL # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA +0C3D;AL # Lo TELUGU SIGN AVAGRAHA +0C3E..0C40;CM # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II +0C41..0C44;CM # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR +0C46..0C48;CM # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI +0C4A..0C4D;CM # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA +0C55..0C56;CM # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK +0C58..0C5A;AL # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA +0C60..0C61;AL # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL +0C62..0C63;CM # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL +0C66..0C6F;NU # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE +0C77;BB # Po TELUGU SIGN SIDDHAM +0C78..0C7E;AL # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR +0C7F;AL # So TELUGU SIGN TUUMU +0C80;AL # Lo KANNADA SIGN SPACING CANDRABINDU +0C81;CM # Mn KANNADA SIGN CANDRABINDU +0C82..0C83;CM # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA +0C84;BB # Po KANNADA SIGN SIDDHAM +0C85..0C8C;AL # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L +0C8E..0C90;AL # Lo [3] KANNADA LETTER E..KANNADA LETTER AI +0C92..0CA8;AL # Lo [23] KANNADA LETTER O..KANNADA LETTER NA +0CAA..0CB3;AL # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA +0CB5..0CB9;AL # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA +0CBC;CM # Mn KANNADA SIGN NUKTA +0CBD;AL # Lo KANNADA SIGN AVAGRAHA +0CBE;CM # Mc KANNADA VOWEL SIGN AA +0CBF;CM # Mn KANNADA VOWEL SIGN I +0CC0..0CC4;CM # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR +0CC6;CM # Mn KANNADA VOWEL SIGN E +0CC7..0CC8;CM # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI +0CCA..0CCB;CM # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO +0CCC..0CCD;CM # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA +0CD5..0CD6;CM # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0CDE;AL # Lo KANNADA LETTER FA +0CE0..0CE1;AL # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL +0CE2..0CE3;CM # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL +0CE6..0CEF;NU # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE +0CF1..0CF2;AL # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA +0D00..0D01;CM # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU +0D02..0D03;CM # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D04..0D0C;AL # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L +0D0E..0D10;AL # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI +0D12..0D3A;AL # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA +0D3B..0D3C;CM # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA +0D3D;AL # Lo MALAYALAM SIGN AVAGRAHA +0D3E..0D40;CM # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II +0D41..0D44;CM # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR +0D46..0D48;CM # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +0D4A..0D4C;CM # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU +0D4D;CM # Mn MALAYALAM SIGN VIRAMA +0D4E;AL # Lo MALAYALAM LETTER DOT REPH +0D4F;AL # So MALAYALAM SIGN PARA +0D54..0D56;AL # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL +0D57;CM # Mc MALAYALAM AU LENGTH MARK +0D58..0D5E;AL # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH +0D5F..0D61;AL # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL +0D62..0D63;CM # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL +0D66..0D6F;NU # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE +0D70..0D78;AL # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS +0D79;PO # So MALAYALAM DATE MARK +0D7A..0D7F;AL # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K +0D81;CM # Mn SINHALA SIGN CANDRABINDU +0D82..0D83;CM # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA +0D85..0D96;AL # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA +0D9A..0DB1;AL # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA +0DB3..0DBB;AL # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA +0DBD;AL # Lo SINHALA LETTER DANTAJA LAYANNA +0DC0..0DC6;AL # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA +0DCA;CM # Mn SINHALA SIGN AL-LAKUNA +0DCF..0DD1;CM # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA +0DD2..0DD4;CM # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6;CM # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8..0DDF;CM # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DE6..0DEF;NU # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE +0DF2..0DF3;CM # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +0DF4;AL # Po SINHALA PUNCTUATION KUNDDALIYA +0E01..0E30;SA # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A +0E31;SA # Mn THAI CHARACTER MAI HAN-AKAT +0E32..0E33;SA # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM +0E34..0E3A;SA # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU +0E3F;PR # Sc THAI CURRENCY SYMBOL BAHT +0E40..0E45;SA # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO +0E46;SA # Lm THAI CHARACTER MAIYAMOK +0E47..0E4E;SA # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN +0E4F;AL # Po THAI CHARACTER FONGMAN +0E50..0E59;NU # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE +0E5A..0E5B;BA # Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT +0E81..0E82;SA # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG +0E84;SA # Lo LAO LETTER KHO TAM +0E86..0E8A;SA # Lo [5] LAO LETTER PALI GHA..LAO LETTER SO TAM +0E8C..0EA3;SA # Lo [24] LAO LETTER PALI JHA..LAO LETTER LO LING +0EA5;SA # Lo LAO LETTER LO LOOT +0EA7..0EB0;SA # Lo [10] LAO LETTER WO..LAO VOWEL SIGN A +0EB1;SA # Mn LAO VOWEL SIGN MAI KAN +0EB2..0EB3;SA # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM +0EB4..0EBC;SA # Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO +0EBD;SA # Lo LAO SEMIVOWEL SIGN NYO +0EC0..0EC4;SA # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI +0EC6;SA # Lm LAO KO LA +0EC8..0ECD;SA # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA +0ED0..0ED9;NU # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE +0EDC..0EDF;SA # Lo [4] LAO HO NO..LAO LETTER KHMU NYO +0F00;AL # Lo TIBETAN SYLLABLE OM +0F01..0F03;BB # So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA +0F04;BB # Po TIBETAN MARK INITIAL YIG MGO MDUN MA +0F05;AL # Po TIBETAN MARK CLOSING YIG MGO SGAB MA +0F06..0F07;BB # Po [2] TIBETAN MARK CARET YIG MGO PHUR SHAD MA..TIBETAN MARK YIG MGO TSHEG SHAD MA +0F08;GL # Po TIBETAN MARK SBRUL SHAD +0F09..0F0A;BB # Po [2] TIBETAN MARK BSKUR YIG MGO..TIBETAN MARK BKA- SHOG YIG MGO +0F0B;BA # Po TIBETAN MARK INTERSYLLABIC TSHEG +0F0C;GL # Po TIBETAN MARK DELIMITER TSHEG BSTAR +0F0D..0F11;EX # Po [5] TIBETAN MARK SHAD..TIBETAN MARK RIN CHEN SPUNGS SHAD +0F12;GL # Po TIBETAN MARK RGYA GRAM SHAD +0F13;AL # So TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN +0F14;EX # Po TIBETAN MARK GTER TSHEG +0F15..0F17;AL # So [3] TIBETAN LOGOTYPE SIGN CHAD RTAGS..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS +0F18..0F19;CM # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F1A..0F1F;AL # So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG +0F20..0F29;NU # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE +0F2A..0F33;AL # No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO +0F34;BA # So TIBETAN MARK BSDUS RTAGS +0F35;CM # Mn TIBETAN MARK NGAS BZUNG NYI ZLA +0F36;AL # So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN +0F37;CM # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F38;AL # So TIBETAN MARK CHE MGO +0F39;CM # Mn TIBETAN MARK TSA -PHRU +0F3A;OP # Ps TIBETAN MARK GUG RTAGS GYON +0F3B;CL # Pe TIBETAN MARK GUG RTAGS GYAS +0F3C;OP # Ps TIBETAN MARK ANG KHANG GYON +0F3D;CL # Pe TIBETAN MARK ANG KHANG GYAS +0F3E..0F3F;CM # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES +0F40..0F47;AL # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA +0F49..0F6C;AL # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA +0F71..0F7E;CM # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO +0F7F;BA # Mc TIBETAN SIGN RNAM BCAD +0F80..0F84;CM # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA +0F85;BA # Po TIBETAN MARK PALUTA +0F86..0F87;CM # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS +0F88..0F8C;AL # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN +0F8D..0F97;CM # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA +0F99..0FBC;CM # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA +0FBE..0FBF;BA # So [2] TIBETAN KU RU KHA..TIBETAN KU RU KHA BZHI MIG CAN +0FC0..0FC5;AL # So [6] TIBETAN CANTILLATION SIGN HEAVY BEAT..TIBETAN SYMBOL RDO RJE +0FC6;CM # Mn TIBETAN SYMBOL PADMA GDAN +0FC7..0FCC;AL # So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL +0FCE..0FCF;AL # So [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM +0FD0..0FD1;BB # Po [2] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK MNYAM YIG GI MGO RGYAN +0FD2;BA # Po TIBETAN MARK NYIS TSHEG +0FD3;BB # Po TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA +0FD4;AL # Po TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA +0FD5..0FD8;AL # So [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS +0FD9..0FDA;GL # Po [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS +1000..102A;SA # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU +102B..102C;SA # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA +102D..1030;SA # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU +1031;SA # Mc MYANMAR VOWEL SIGN E +1032..1037;SA # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW +1038;SA # Mc MYANMAR SIGN VISARGA +1039..103A;SA # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT +103B..103C;SA # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA +103D..103E;SA # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA +103F;SA # Lo MYANMAR LETTER GREAT SA +1040..1049;NU # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE +104A..104B;BA # Po [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION +104C..104F;AL # Po [4] MYANMAR SYMBOL LOCATIVE..MYANMAR SYMBOL GENITIVE +1050..1055;SA # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL +1056..1057;SA # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR +1058..1059;SA # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL +105A..105D;SA # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE +105E..1060;SA # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA +1061;SA # Lo MYANMAR LETTER SGAW KAREN SHA +1062..1064;SA # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO +1065..1066;SA # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA +1067..106D;SA # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5 +106E..1070;SA # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA +1071..1074;SA # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE +1075..1081;SA # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA +1082;SA # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA +1083..1084;SA # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E +1085..1086;SA # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y +1087..108C;SA # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3 +108D;SA # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE +108E;SA # Lo MYANMAR LETTER RUMAI PALAUNG FA +108F;SA # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5 +1090..1099;NU # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE +109A..109C;SA # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A +109D;SA # Mn MYANMAR VOWEL SIGN AITON AI +109E..109F;SA # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION +10A0..10C5;AL # Lu [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE +10C7;AL # Lu GEORGIAN CAPITAL LETTER YN +10CD;AL # Lu GEORGIAN CAPITAL LETTER AEN +10D0..10FA;AL # Ll [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN +10FB;AL # Po GEORGIAN PARAGRAPH SEPARATOR +10FC;AL # Lm MODIFIER LETTER GEORGIAN NAR +10FD..10FF;AL # Ll [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN +1100..115F;JL # Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER +1160..11A7;JV # Lo [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE +11A8..11FF;JT # Lo [88] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG SSANGNIEUN +1200..1248;AL # Lo [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA +124A..124D;AL # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE +1250..1256;AL # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO +1258;AL # Lo ETHIOPIC SYLLABLE QHWA +125A..125D;AL # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE +1260..1288;AL # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA +128A..128D;AL # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE +1290..12B0;AL # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA +12B2..12B5;AL # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE +12B8..12BE;AL # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO +12C0;AL # Lo ETHIOPIC SYLLABLE KXWA +12C2..12C5;AL # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE +12C8..12D6;AL # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O +12D8..1310;AL # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA +1312..1315;AL # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE +1318..135A;AL # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA +135D..135F;CM # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK +1360;AL # Po ETHIOPIC SECTION MARK +1361;BA # Po ETHIOPIC WORDSPACE +1362..1368;AL # Po [7] ETHIOPIC FULL STOP..ETHIOPIC PARAGRAPH SEPARATOR +1369..137C;AL # No [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND +1380..138F;AL # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE +1390..1399;AL # So [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT +13A0..13F5;AL # Lu [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +13F8..13FD;AL # Ll [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV +1400;BA # Pd CANADIAN SYLLABICS HYPHEN +1401..166C;AL # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA +166D;AL # So CANADIAN SYLLABICS CHI SIGN +166E;AL # Po CANADIAN SYLLABICS FULL STOP +166F..167F;AL # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W +1680;BA # Zs OGHAM SPACE MARK +1681..169A;AL # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH +169B;OP # Ps OGHAM FEATHER MARK +169C;CL # Pe OGHAM REVERSED FEATHER MARK +16A0..16EA;AL # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X +16EB..16ED;BA # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION +16EE..16F0;AL # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL +16F1..16F8;AL # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC +1700..170C;AL # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA +170E..1711;AL # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA +1712..1714;CM # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA +1720..1731;AL # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA +1732..1734;CM # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD +1735..1736;BA # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION +1740..1751;AL # Lo [18] BUHID LETTER A..BUHID LETTER HA +1752..1753;CM # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U +1760..176C;AL # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA +176E..1770;AL # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA +1772..1773;CM # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U +1780..17B3;SA # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU +17B4..17B5;SA # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA +17B6;SA # Mc KHMER VOWEL SIGN AA +17B7..17BD;SA # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA +17BE..17C5;SA # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU +17C6;SA # Mn KHMER SIGN NIKAHIT +17C7..17C8;SA # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU +17C9..17D3;SA # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT +17D4..17D5;BA # Po [2] KHMER SIGN KHAN..KHMER SIGN BARIYOOSAN +17D6;NS # Po KHMER SIGN CAMNUC PII KUUH +17D7;SA # Lm KHMER SIGN LEK TOO +17D8;BA # Po KHMER SIGN BEYYAL +17D9;AL # Po KHMER SIGN PHNAEK MUAN +17DA;BA # Po KHMER SIGN KOOMUUT +17DB;PR # Sc KHMER CURRENCY SYMBOL RIEL +17DC;SA # Lo KHMER SIGN AVAKRAHASANYA +17DD;SA # Mn KHMER SIGN ATTHACAN +17E0..17E9;NU # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE +17F0..17F9;AL # No [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON +1800..1801;AL # Po [2] MONGOLIAN BIRGA..MONGOLIAN ELLIPSIS +1802..1803;EX # Po [2] MONGOLIAN COMMA..MONGOLIAN FULL STOP +1804..1805;BA # Po [2] MONGOLIAN COLON..MONGOLIAN FOUR DOTS +1806;BB # Pd MONGOLIAN TODO SOFT HYPHEN +1807;AL # Po MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER +1808..1809;EX # Po [2] MONGOLIAN MANCHU COMMA..MONGOLIAN MANCHU FULL STOP +180A;AL # Po MONGOLIAN NIRUGU +180B..180D;CM # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +180E;GL # Cf MONGOLIAN VOWEL SEPARATOR +1810..1819;NU # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE +1820..1842;AL # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI +1843;AL # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN +1844..1878;AL # Lo [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS +1880..1884;AL # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1885..1886;CM # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +1887..18A8;AL # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA +18A9;CM # Mn MONGOLIAN LETTER ALI GALI DAGALGA +18AA;AL # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA +18B0..18F5;AL # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S +1900..191E;AL # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA +1920..1922;CM # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U +1923..1926;CM # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU +1927..1928;CM # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O +1929..192B;CM # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA +1930..1931;CM # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA +1932;CM # Mn LIMBU SMALL LETTER ANUSVARA +1933..1938;CM # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA +1939..193B;CM # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I +1940;AL # So LIMBU SIGN LOO +1944..1945;EX # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK +1946..194F;NU # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE +1950..196D;SA # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI +1970..1974;SA # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6 +1980..19AB;SA # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA +19B0..19C9;SA # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2 +19D0..19D9;NU # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE +19DA;SA # No NEW TAI LUE THAM DIGIT ONE +19DE..19DF;SA # So [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV +19E0..19FF;AL # So [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC +1A00..1A16;AL # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA +1A17..1A18;CM # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U +1A19..1A1A;CM # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O +1A1B;CM # Mn BUGINESE VOWEL SIGN AE +1A1E..1A1F;AL # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION +1A20..1A54;SA # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA +1A55;SA # Mc TAI THAM CONSONANT SIGN MEDIAL RA +1A56;SA # Mn TAI THAM CONSONANT SIGN MEDIAL LA +1A57;SA # Mc TAI THAM CONSONANT SIGN LA TANG LAI +1A58..1A5E;SA # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA +1A60;SA # Mn TAI THAM SIGN SAKOT +1A61;SA # Mc TAI THAM VOWEL SIGN A +1A62;SA # Mn TAI THAM VOWEL SIGN MAI SAT +1A63..1A64;SA # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA +1A65..1A6C;SA # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW +1A6D..1A72;SA # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI +1A73..1A7C;SA # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN +1A7F;CM # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT +1A80..1A89;NU # Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE +1A90..1A99;NU # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE +1AA0..1AA6;SA # Po [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA +1AA7;SA # Lm TAI THAM SIGN MAI YAMOK +1AA8..1AAD;SA # Po [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG +1AB0..1ABD;CM # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW +1ABE;CM # Me COMBINING PARENTHESES OVERLAY +1ABF..1AC0;CM # Mn [2] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER TURNED W BELOW +1B00..1B03;CM # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG +1B04;CM # Mc BALINESE SIGN BISAH +1B05..1B33;AL # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA +1B34;CM # Mn BALINESE SIGN REREKAN +1B35;CM # Mc BALINESE VOWEL SIGN TEDUNG +1B36..1B3A;CM # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA +1B3B;CM # Mc BALINESE VOWEL SIGN RA REPA TEDUNG +1B3C;CM # Mn BALINESE VOWEL SIGN LA LENGA +1B3D..1B41;CM # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG +1B42;CM # Mn BALINESE VOWEL SIGN PEPET +1B43..1B44;CM # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG +1B45..1B4B;AL # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK +1B50..1B59;NU # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE +1B5A..1B5B;BA # Po [2] BALINESE PANTI..BALINESE PAMADA +1B5C;AL # Po BALINESE WINDU +1B5D..1B60;BA # Po [4] BALINESE CARIK PAMUNGKAH..BALINESE PAMENENG +1B61..1B6A;AL # So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE +1B6B..1B73;CM # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG +1B74..1B7C;AL # So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING +1B80..1B81;CM # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR +1B82;CM # Mc SUNDANESE SIGN PANGWISAD +1B83..1BA0;AL # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA +1BA1;CM # Mc SUNDANESE CONSONANT SIGN PAMINGKAL +1BA2..1BA5;CM # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU +1BA6..1BA7;CM # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG +1BA8..1BA9;CM # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG +1BAA;CM # Mc SUNDANESE SIGN PAMAAEH +1BAB..1BAD;CM # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BAE..1BAF;AL # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA +1BB0..1BB9;NU # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE +1BBA..1BBF;AL # Lo [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M +1BC0..1BE5;AL # Lo [38] BATAK LETTER A..BATAK LETTER U +1BE6;CM # Mn BATAK SIGN TOMPI +1BE7;CM # Mc BATAK VOWEL SIGN E +1BE8..1BE9;CM # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE +1BEA..1BEC;CM # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O +1BED;CM # Mn BATAK VOWEL SIGN KARO O +1BEE;CM # Mc BATAK VOWEL SIGN U +1BEF..1BF1;CM # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H +1BF2..1BF3;CM # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN +1BFC..1BFF;AL # Po [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT +1C00..1C23;AL # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A +1C24..1C2B;CM # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU +1C2C..1C33;CM # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T +1C34..1C35;CM # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG +1C36..1C37;CM # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA +1C3B..1C3F;BA # Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK +1C40..1C49;NU # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE +1C4D..1C4F;AL # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA +1C50..1C59;NU # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE +1C5A..1C77;AL # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH +1C78..1C7D;AL # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD +1C7E..1C7F;BA # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +1C80..1C88;AL # Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C90..1CBA;AL # Lu [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN +1CBD..1CBF;AL # Lu [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN +1CC0..1CC7;AL # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA +1CD0..1CD2;CM # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA +1CD3;AL # Po VEDIC SIGN NIHSHVASA +1CD4..1CE0;CM # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA +1CE1;CM # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA +1CE2..1CE8;CM # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL +1CE9..1CEC;AL # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL +1CED;CM # Mn VEDIC SIGN TIRYAK +1CEE..1CF3;AL # Lo [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA +1CF4;CM # Mn VEDIC TONE CANDRA ABOVE +1CF5..1CF6;AL # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA +1CF7;CM # Mc VEDIC SIGN ATIKRAMA +1CF8..1CF9;CM # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE +1CFA;AL # Lo VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA +1D00..1D2B;AL # Ll [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL +1D2C..1D6A;AL # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI +1D6B..1D77;AL # Ll [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G +1D78;AL # Lm MODIFIER LETTER CYRILLIC EN +1D79..1D7F;AL # Ll [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE +1D80..1D9A;AL # Ll [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK +1D9B..1DBF;AL # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA +1DC0..1DF9;CM # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF;CM # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1E00..1EFF;AL # L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP +1F00..1F15;AL # L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F18..1F1D;AL # Lu [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F20..1F45;AL # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F48..1F4D;AL # Lu [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50..1F57;AL # Ll [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F59;AL # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B;AL # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D;AL # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F..1F7D;AL # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA +1F80..1FB4;AL # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6..1FBC;AL # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBD;AL # Sk GREEK KORONIS +1FBE;AL # Ll GREEK PROSGEGRAMMENI +1FBF..1FC1;AL # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI +1FC2..1FC4;AL # Ll [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6..1FCC;AL # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCD..1FCF;AL # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI +1FD0..1FD3;AL # Ll [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6..1FDB;AL # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA +1FDD..1FDF;AL # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI +1FE0..1FEC;AL # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA +1FED..1FEF;AL # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA +1FF2..1FF4;AL # Ll [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6..1FFC;AL # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFD;BB # Sk GREEK OXIA +1FFE;AL # Sk GREEK DASIA +2000..2006;BA # Zs [7] EN QUAD..SIX-PER-EM SPACE +2007;GL # Zs FIGURE SPACE +2008..200A;BA # Zs [3] PUNCTUATION SPACE..HAIR SPACE +200B;ZW # Cf ZERO WIDTH SPACE +200C;CM # Cf ZERO WIDTH NON-JOINER +200D;ZWJ # Cf ZERO WIDTH JOINER +200E..200F;CM # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK +2010;BA # Pd HYPHEN +2011;GL # Pd NON-BREAKING HYPHEN +2012..2013;BA # Pd [2] FIGURE DASH..EN DASH +2014;B2 # Pd EM DASH +2015;AI # Pd HORIZONTAL BAR +2016;AI # Po DOUBLE VERTICAL LINE +2017;AL # Po DOUBLE LOW LINE +2018;QU # Pi LEFT SINGLE QUOTATION MARK +2019;QU # Pf RIGHT SINGLE QUOTATION MARK +201A;OP # Ps SINGLE LOW-9 QUOTATION MARK +201B..201C;QU # Pi [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK +201D;QU # Pf RIGHT DOUBLE QUOTATION MARK +201E;OP # Ps DOUBLE LOW-9 QUOTATION MARK +201F;QU # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK +2020..2021;AI # Po [2] DAGGER..DOUBLE DAGGER +2022..2023;AL # Po [2] BULLET..TRIANGULAR BULLET +2024..2026;IN # Po [3] ONE DOT LEADER..HORIZONTAL ELLIPSIS +2027;BA # Po HYPHENATION POINT +2028;BK # Zl LINE SEPARATOR +2029;BK # Zp PARAGRAPH SEPARATOR +202A..202E;CM # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE +202F;GL # Zs NARROW NO-BREAK SPACE +2030..2037;PO # Po [8] PER MILLE SIGN..REVERSED TRIPLE PRIME +2038;AL # Po CARET +2039;QU # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A;QU # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +203B;AI # Po REFERENCE MARK +203C..203D;NS # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG +203E;AL # Po OVERLINE +203F..2040;AL # Pc [2] UNDERTIE..CHARACTER TIE +2041..2043;AL # Po [3] CARET INSERTION POINT..HYPHEN BULLET +2044;IS # Sm FRACTION SLASH +2045;OP # Ps LEFT SQUARE BRACKET WITH QUILL +2046;CL # Pe RIGHT SQUARE BRACKET WITH QUILL +2047..2049;NS # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK +204A..2051;AL # Po [8] TIRONIAN SIGN ET..TWO ASTERISKS ALIGNED VERTICALLY +2052;AL # Sm COMMERCIAL MINUS SIGN +2053;AL # Po SWUNG DASH +2054;AL # Pc INVERTED UNDERTIE +2055;AL # Po FLOWER PUNCTUATION MARK +2056;BA # Po THREE DOT PUNCTUATION +2057;AL # Po QUADRUPLE PRIME +2058..205B;BA # Po [4] FOUR DOT PUNCTUATION..FOUR DOT MARK +205C;AL # Po DOTTED CROSS +205D..205E;BA # Po [2] TRICOLON..VERTICAL FOUR DOTS +205F;BA # Zs MEDIUM MATHEMATICAL SPACE +2060;WJ # Cf WORD JOINER +2061..2064;AL # Cf [4] FUNCTION APPLICATION..INVISIBLE PLUS +2066..206F;CM # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES +2070;AL # No SUPERSCRIPT ZERO +2071;AL # Lm SUPERSCRIPT LATIN SMALL LETTER I +2074;AI # No SUPERSCRIPT FOUR +2075..2079;AL # No [5] SUPERSCRIPT FIVE..SUPERSCRIPT NINE +207A..207C;AL # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN +207D;OP # Ps SUPERSCRIPT LEFT PARENTHESIS +207E;CL # Pe SUPERSCRIPT RIGHT PARENTHESIS +207F;AI # Lm SUPERSCRIPT LATIN SMALL LETTER N +2080;AL # No SUBSCRIPT ZERO +2081..2084;AI # No [4] SUBSCRIPT ONE..SUBSCRIPT FOUR +2085..2089;AL # No [5] SUBSCRIPT FIVE..SUBSCRIPT NINE +208A..208C;AL # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN +208D;OP # Ps SUBSCRIPT LEFT PARENTHESIS +208E;CL # Pe SUBSCRIPT RIGHT PARENTHESIS +2090..209C;AL # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T +20A0..20A6;PR # Sc [7] EURO-CURRENCY SIGN..NAIRA SIGN +20A7;PO # Sc PESETA SIGN +20A8..20B5;PR # Sc [14] RUPEE SIGN..CEDI SIGN +20B6;PO # Sc LIVRE TOURNOIS SIGN +20B7..20BA;PR # Sc [4] SPESMILO SIGN..TURKISH LIRA SIGN +20BB;PO # Sc NORDIC MARK SIGN +20BC..20BD;PR # Sc [2] MANAT SIGN..RUBLE SIGN +20BE;PO # Sc LARI SIGN +20BF;PR # Sc BITCOIN SIGN +20C0..20CF;PR # Cn [16] .. +20D0..20DC;CM # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE +20DD..20E0;CM # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH +20E1;CM # Mn COMBINING LEFT RIGHT ARROW ABOVE +20E2..20E4;CM # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE +20E5..20F0;CM # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE +2100..2101;AL # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT +2102;AL # Lu DOUBLE-STRUCK CAPITAL C +2103;PO # So DEGREE CELSIUS +2104;AL # So CENTRE LINE SYMBOL +2105;AI # So CARE OF +2106;AL # So CADA UNA +2107;AL # Lu EULER CONSTANT +2108;AL # So SCRUPLE +2109;PO # So DEGREE FAHRENHEIT +210A..2112;AL # L& [9] SCRIPT SMALL G..SCRIPT CAPITAL L +2113;AI # Ll SCRIPT SMALL L +2114;AL # So L B BAR SYMBOL +2115;AL # Lu DOUBLE-STRUCK CAPITAL N +2116;PR # So NUMERO SIGN +2117;AL # So SOUND RECORDING COPYRIGHT +2118;AL # Sm SCRIPT CAPITAL P +2119..211D;AL # Lu [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R +211E..2120;AL # So [3] PRESCRIPTION TAKE..SERVICE MARK +2121..2122;AI # So [2] TELEPHONE SIGN..TRADE MARK SIGN +2123;AL # So VERSICLE +2124;AL # Lu DOUBLE-STRUCK CAPITAL Z +2125;AL # So OUNCE SIGN +2126;AL # Lu OHM SIGN +2127;AL # So INVERTED OHM SIGN +2128;AL # Lu BLACK-LETTER CAPITAL Z +2129;AL # So TURNED GREEK SMALL LETTER IOTA +212A;AL # Lu KELVIN SIGN +212B;AI # Lu ANGSTROM SIGN +212C..212D;AL # Lu [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C +212E;AL # So ESTIMATED SYMBOL +212F..2134;AL # L& [6] SCRIPT SMALL E..SCRIPT SMALL O +2135..2138;AL # Lo [4] ALEF SYMBOL..DALET SYMBOL +2139;AL # Ll INFORMATION SOURCE +213A..213B;AL # So [2] ROTATED CAPITAL Q..FACSIMILE SIGN +213C..213F;AL # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI +2140..2144;AL # Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y +2145..2149;AL # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J +214A;AL # So PROPERTY LINE +214B;AL # Sm TURNED AMPERSAND +214C..214D;AL # So [2] PER SIGN..AKTIESELSKAB +214E;AL # Ll TURNED SMALL F +214F;AL # So SYMBOL FOR SAMARITAN SOURCE +2150..2153;AL # No [4] VULGAR FRACTION ONE SEVENTH..VULGAR FRACTION ONE THIRD +2154..2155;AI # No [2] VULGAR FRACTION TWO THIRDS..VULGAR FRACTION ONE FIFTH +2156..215A;AL # No [5] VULGAR FRACTION TWO FIFTHS..VULGAR FRACTION FIVE SIXTHS +215B;AI # No VULGAR FRACTION ONE EIGHTH +215C..215D;AL # No [2] VULGAR FRACTION THREE EIGHTHS..VULGAR FRACTION FIVE EIGHTHS +215E;AI # No VULGAR FRACTION SEVEN EIGHTHS +215F;AL # No FRACTION NUMERATOR ONE +2160..216B;AI # Nl [12] ROMAN NUMERAL ONE..ROMAN NUMERAL TWELVE +216C..216F;AL # Nl [4] ROMAN NUMERAL FIFTY..ROMAN NUMERAL ONE THOUSAND +2170..2179;AI # Nl [10] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL TEN +217A..2182;AL # Nl [9] SMALL ROMAN NUMERAL ELEVEN..ROMAN NUMERAL TEN THOUSAND +2183..2184;AL # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C +2185..2188;AL # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND +2189;AI # No VULGAR FRACTION ZERO THIRDS +218A..218B;AL # So [2] TURNED DIGIT TWO..TURNED DIGIT THREE +2190..2194;AI # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW +2195..2199;AI # So [5] UP DOWN ARROW..SOUTH WEST ARROW +219A..219B;AL # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE +219C..219F;AL # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW +21A0;AL # Sm RIGHTWARDS TWO HEADED ARROW +21A1..21A2;AL # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL +21A3;AL # Sm RIGHTWARDS ARROW WITH TAIL +21A4..21A5;AL # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR +21A6;AL # Sm RIGHTWARDS ARROW FROM BAR +21A7..21AD;AL # So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW +21AE;AL # Sm LEFT RIGHT ARROW WITH STROKE +21AF..21CD;AL # So [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE +21CE..21CF;AL # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE +21D0..21D1;AL # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW +21D2;AI # Sm RIGHTWARDS DOUBLE ARROW +21D3;AL # So DOWNWARDS DOUBLE ARROW +21D4;AI # Sm LEFT RIGHT DOUBLE ARROW +21D5..21F3;AL # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW +21F4..21FF;AL # Sm [12] RIGHT ARROW WITH SMALL CIRCLE..LEFT RIGHT OPEN-HEADED ARROW +2200;AI # Sm FOR ALL +2201;AL # Sm COMPLEMENT +2202..2203;AI # Sm [2] PARTIAL DIFFERENTIAL..THERE EXISTS +2204..2206;AL # Sm [3] THERE DOES NOT EXIST..INCREMENT +2207..2208;AI # Sm [2] NABLA..ELEMENT OF +2209..220A;AL # Sm [2] NOT AN ELEMENT OF..SMALL ELEMENT OF +220B;AI # Sm CONTAINS AS MEMBER +220C..220E;AL # Sm [3] DOES NOT CONTAIN AS MEMBER..END OF PROOF +220F;AI # Sm N-ARY PRODUCT +2210;AL # Sm N-ARY COPRODUCT +2211;AI # Sm N-ARY SUMMATION +2212..2213;PR # Sm [2] MINUS SIGN..MINUS-OR-PLUS SIGN +2214;AL # Sm DOT PLUS +2215;AI # Sm DIVISION SLASH +2216..2219;AL # Sm [4] SET MINUS..BULLET OPERATOR +221A;AI # Sm SQUARE ROOT +221B..221C;AL # Sm [2] CUBE ROOT..FOURTH ROOT +221D..2220;AI # Sm [4] PROPORTIONAL TO..ANGLE +2221..2222;AL # Sm [2] MEASURED ANGLE..SPHERICAL ANGLE +2223;AI # Sm DIVIDES +2224;AL # Sm DOES NOT DIVIDE +2225;AI # Sm PARALLEL TO +2226;AL # Sm NOT PARALLEL TO +2227..222C;AI # Sm [6] LOGICAL AND..DOUBLE INTEGRAL +222D;AL # Sm TRIPLE INTEGRAL +222E;AI # Sm CONTOUR INTEGRAL +222F..2233;AL # Sm [5] SURFACE INTEGRAL..ANTICLOCKWISE CONTOUR INTEGRAL +2234..2237;AI # Sm [4] THEREFORE..PROPORTION +2238..223B;AL # Sm [4] DOT MINUS..HOMOTHETIC +223C..223D;AI # Sm [2] TILDE OPERATOR..REVERSED TILDE +223E..2247;AL # Sm [10] INVERTED LAZY S..NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO +2248;AI # Sm ALMOST EQUAL TO +2249..224B;AL # Sm [3] NOT ALMOST EQUAL TO..TRIPLE TILDE +224C;AI # Sm ALL EQUAL TO +224D..2251;AL # Sm [5] EQUIVALENT TO..GEOMETRICALLY EQUAL TO +2252;AI # Sm APPROXIMATELY EQUAL TO OR THE IMAGE OF +2253..225F;AL # Sm [13] IMAGE OF OR APPROXIMATELY EQUAL TO..QUESTIONED EQUAL TO +2260..2261;AI # Sm [2] NOT EQUAL TO..IDENTICAL TO +2262..2263;AL # Sm [2] NOT IDENTICAL TO..STRICTLY EQUIVALENT TO +2264..2267;AI # Sm [4] LESS-THAN OR EQUAL TO..GREATER-THAN OVER EQUAL TO +2268..2269;AL # Sm [2] LESS-THAN BUT NOT EQUAL TO..GREATER-THAN BUT NOT EQUAL TO +226A..226B;AI # Sm [2] MUCH LESS-THAN..MUCH GREATER-THAN +226C..226D;AL # Sm [2] BETWEEN..NOT EQUIVALENT TO +226E..226F;AI # Sm [2] NOT LESS-THAN..NOT GREATER-THAN +2270..2281;AL # Sm [18] NEITHER LESS-THAN NOR EQUAL TO..DOES NOT SUCCEED +2282..2283;AI # Sm [2] SUBSET OF..SUPERSET OF +2284..2285;AL # Sm [2] NOT A SUBSET OF..NOT A SUPERSET OF +2286..2287;AI # Sm [2] SUBSET OF OR EQUAL TO..SUPERSET OF OR EQUAL TO +2288..2294;AL # Sm [13] NEITHER A SUBSET OF NOR EQUAL TO..SQUARE CUP +2295;AI # Sm CIRCLED PLUS +2296..2298;AL # Sm [3] CIRCLED MINUS..CIRCLED DIVISION SLASH +2299;AI # Sm CIRCLED DOT OPERATOR +229A..22A4;AL # Sm [11] CIRCLED RING OPERATOR..DOWN TACK +22A5;AI # Sm UP TACK +22A6..22BE;AL # Sm [25] ASSERTION..RIGHT ANGLE WITH ARC +22BF;AI # Sm RIGHT TRIANGLE +22C0..22EE;AL # Sm [47] N-ARY LOGICAL AND..VERTICAL ELLIPSIS +22EF;IN # Sm MIDLINE HORIZONTAL ELLIPSIS +22F0..22FF;AL # Sm [16] UP RIGHT DIAGONAL ELLIPSIS..Z NOTATION BAG MEMBERSHIP +2300..2307;AL # So [8] DIAMETER SIGN..WAVY LINE +2308;OP # Ps LEFT CEILING +2309;CL # Pe RIGHT CEILING +230A;OP # Ps LEFT FLOOR +230B;CL # Pe RIGHT FLOOR +230C..2311;AL # So [6] BOTTOM RIGHT CROP..SQUARE LOZENGE +2312;AI # So ARC +2313..2319;AL # So [7] SEGMENT..TURNED NOT SIGN +231A..231B;ID # So [2] WATCH..HOURGLASS +231C..231F;AL # So [4] TOP LEFT CORNER..BOTTOM RIGHT CORNER +2320..2321;AL # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL +2322..2328;AL # So [7] FROWN..KEYBOARD +2329;OP # Ps LEFT-POINTING ANGLE BRACKET +232A;CL # Pe RIGHT-POINTING ANGLE BRACKET +232B..237B;AL # So [81] ERASE TO THE LEFT..NOT CHECK MARK +237C;AL # Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW +237D..239A;AL # So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL +239B..23B3;AL # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM +23B4..23DB;AL # So [40] TOP SQUARE BRACKET..FUSE +23DC..23E1;AL # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET +23E2..23EF;AL # So [14] WHITE TRAPEZIUM..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR +23F0..23F3;ID # So [4] ALARM CLOCK..HOURGLASS WITH FLOWING SAND +23F4..23FF;AL # So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL +2400..2426;AL # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO +2440..244A;AL # So [11] OCR HOOK..OCR DOUBLE BACKSLASH +2460..249B;AI # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP +249C..24E9;AI # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z +24EA..24FE;AI # No [21] CIRCLED DIGIT ZERO..DOUBLE CIRCLED NUMBER TEN +24FF;AL # No NEGATIVE CIRCLED DIGIT ZERO +2500..254B;AI # So [76] BOX DRAWINGS LIGHT HORIZONTAL..BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL +254C..254F;AL # So [4] BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL..BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL +2550..2574;AI # So [37] BOX DRAWINGS DOUBLE HORIZONTAL..BOX DRAWINGS LIGHT LEFT +2575..257F;AL # So [11] BOX DRAWINGS LIGHT UP..BOX DRAWINGS HEAVY UP AND LIGHT DOWN +2580..258F;AI # So [16] UPPER HALF BLOCK..LEFT ONE EIGHTH BLOCK +2590..2591;AL # So [2] RIGHT HALF BLOCK..LIGHT SHADE +2592..2595;AI # So [4] MEDIUM SHADE..RIGHT ONE EIGHTH BLOCK +2596..259F;AL # So [10] QUADRANT LOWER LEFT..QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT +25A0..25A1;AI # So [2] BLACK SQUARE..WHITE SQUARE +25A2;AL # So WHITE SQUARE WITH ROUNDED CORNERS +25A3..25A9;AI # So [7] WHITE SQUARE CONTAINING BLACK SMALL SQUARE..SQUARE WITH DIAGONAL CROSSHATCH FILL +25AA..25B1;AL # So [8] BLACK SMALL SQUARE..WHITE PARALLELOGRAM +25B2..25B3;AI # So [2] BLACK UP-POINTING TRIANGLE..WHITE UP-POINTING TRIANGLE +25B4..25B5;AL # So [2] BLACK UP-POINTING SMALL TRIANGLE..WHITE UP-POINTING SMALL TRIANGLE +25B6;AI # So BLACK RIGHT-POINTING TRIANGLE +25B7;AI # Sm WHITE RIGHT-POINTING TRIANGLE +25B8..25BB;AL # So [4] BLACK RIGHT-POINTING SMALL TRIANGLE..WHITE RIGHT-POINTING POINTER +25BC..25BD;AI # So [2] BLACK DOWN-POINTING TRIANGLE..WHITE DOWN-POINTING TRIANGLE +25BE..25BF;AL # So [2] BLACK DOWN-POINTING SMALL TRIANGLE..WHITE DOWN-POINTING SMALL TRIANGLE +25C0;AI # So BLACK LEFT-POINTING TRIANGLE +25C1;AI # Sm WHITE LEFT-POINTING TRIANGLE +25C2..25C5;AL # So [4] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE LEFT-POINTING POINTER +25C6..25C8;AI # So [3] BLACK DIAMOND..WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND +25C9..25CA;AL # So [2] FISHEYE..LOZENGE +25CB;AI # So WHITE CIRCLE +25CC..25CD;AL # So [2] DOTTED CIRCLE..CIRCLE WITH VERTICAL FILL +25CE..25D1;AI # So [4] BULLSEYE..CIRCLE WITH RIGHT HALF BLACK +25D2..25E1;AL # So [16] CIRCLE WITH LOWER HALF BLACK..LOWER HALF CIRCLE +25E2..25E5;AI # So [4] BLACK LOWER RIGHT TRIANGLE..BLACK UPPER RIGHT TRIANGLE +25E6..25EE;AL # So [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK +25EF;AI # So LARGE CIRCLE +25F0..25F7;AL # So [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT +25F8..25FF;AL # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE +2600..2603;ID # So [4] BLACK SUN WITH RAYS..SNOWMAN +2604;AL # So COMET +2605..2606;AI # So [2] BLACK STAR..WHITE STAR +2607..2608;AL # So [2] LIGHTNING..THUNDERSTORM +2609;AI # So SUN +260A..260D;AL # So [4] ASCENDING NODE..OPPOSITION +260E..260F;AI # So [2] BLACK TELEPHONE..WHITE TELEPHONE +2610..2613;AL # So [4] BALLOT BOX..SALTIRE +2614..2615;ID # So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE +2616..2617;AI # So [2] WHITE SHOGI PIECE..BLACK SHOGI PIECE +2618;ID # So SHAMROCK +2619;AL # So REVERSED ROTATED FLORAL HEART BULLET +261A..261C;ID # So [3] BLACK LEFT POINTING INDEX..WHITE LEFT POINTING INDEX +261D;EB # So WHITE UP POINTING INDEX +261E..261F;ID # So [2] WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX +2620..2638;AL # So [25] SKULL AND CROSSBONES..WHEEL OF DHARMA +2639..263B;ID # So [3] WHITE FROWNING FACE..BLACK SMILING FACE +263C..263F;AL # So [4] WHITE SUN WITH RAYS..MERCURY +2640;AI # So FEMALE SIGN +2641;AL # So EARTH +2642;AI # So MALE SIGN +2643..265F;AL # So [29] JUPITER..BLACK CHESS PAWN +2660..2661;AI # So [2] BLACK SPADE SUIT..WHITE HEART SUIT +2662;AL # So WHITE DIAMOND SUIT +2663..2665;AI # So [3] BLACK CLUB SUIT..BLACK HEART SUIT +2666;AL # So BLACK DIAMOND SUIT +2667;AI # So WHITE CLUB SUIT +2668;ID # So HOT SPRINGS +2669..266A;AI # So [2] QUARTER NOTE..EIGHTH NOTE +266B;AL # So BEAMED EIGHTH NOTES +266C..266D;AI # So [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN +266E;AL # So MUSIC NATURAL SIGN +266F;AI # Sm MUSIC SHARP SIGN +2670..267E;AL # So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN +267F;ID # So WHEELCHAIR SYMBOL +2680..269D;AL # So [30] DIE FACE-1..OUTLINED WHITE STAR +269E..269F;AI # So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT +26A0..26BC;AL # So [29] WARNING SIGN..SESQUIQUADRATE +26BD..26C8;ID # So [12] SOCCER BALL..THUNDER CLOUD AND RAIN +26C9..26CC;AI # So [4] TURNED WHITE SHOGI PIECE..CROSSING LANES +26CD;ID # So DISABLED CAR +26CE;AL # So OPHIUCHUS +26CF..26D1;ID # So [3] PICK..HELMET WITH WHITE CROSS +26D2;AI # So CIRCLED CROSSING LANES +26D3..26D4;ID # So [2] CHAINS..NO ENTRY +26D5..26D7;AI # So [3] ALTERNATE ONE-WAY LEFT WAY TRAFFIC..WHITE TWO-WAY LEFT WAY TRAFFIC +26D8..26D9;ID # So [2] BLACK LEFT LANE MERGE..WHITE LEFT LANE MERGE +26DA..26DB;AI # So [2] DRIVE SLOW SIGN..HEAVY WHITE DOWN-POINTING TRIANGLE +26DC;ID # So LEFT CLOSED ENTRY +26DD..26DE;AI # So [2] SQUARED SALTIRE..FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARE +26DF..26E1;ID # So [3] BLACK TRUCK..RESTRICTED LEFT ENTRY-2 +26E2;AL # So ASTRONOMICAL SYMBOL FOR URANUS +26E3;AI # So HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE +26E4..26E7;AL # So [4] PENTAGRAM..INVERTED PENTAGRAM +26E8..26E9;AI # So [2] BLACK CROSS ON SHIELD..SHINTO SHRINE +26EA;ID # So CHURCH +26EB..26F0;AI # So [6] CASTLE..MOUNTAIN +26F1..26F5;ID # So [5] UMBRELLA ON GROUND..SAILBOAT +26F6;AI # So SQUARE FOUR CORNERS +26F7..26F8;ID # So [2] SKIER..ICE SKATE +26F9;EB # So PERSON WITH BALL +26FA;ID # So TENT +26FB..26FC;AI # So [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL +26FD..26FF;ID # So [3] FUEL PUMP..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE +2700..2704;ID # So [5] BLACK SAFETY SCISSORS..WHITE SCISSORS +2705..2707;AL # So [3] WHITE HEAVY CHECK MARK..TAPE DRIVE +2708..2709;ID # So [2] AIRPLANE..ENVELOPE +270A..270D;EB # So [4] RAISED FIST..WRITING HAND +270E..2756;AL # So [73] LOWER RIGHT PENCIL..BLACK DIAMOND MINUS WHITE X +2757;AI # So HEAVY EXCLAMATION MARK SYMBOL +2758..275A;AL # So [3] LIGHT VERTICAL BAR..HEAVY VERTICAL BAR +275B..2760;QU # So [6] HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT..HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT +2761;AL # So CURVED STEM PARAGRAPH SIGN ORNAMENT +2762..2763;EX # So [2] HEAVY EXCLAMATION MARK ORNAMENT..HEAVY HEART EXCLAMATION MARK ORNAMENT +2764;ID # So HEAVY BLACK HEART +2765..2767;AL # So [3] ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET +2768;OP # Ps MEDIUM LEFT PARENTHESIS ORNAMENT +2769;CL # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT +276A;OP # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT +276B;CL # Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT +276C;OP # Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT +276D;CL # Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT +276E;OP # Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT +276F;CL # Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT +2770;OP # Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT +2771;CL # Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT +2772;OP # Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT +2773;CL # Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT +2774;OP # Ps MEDIUM LEFT CURLY BRACKET ORNAMENT +2775;CL # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT +2776..2793;AI # No [30] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN +2794..27BF;AL # So [44] HEAVY WIDE-HEADED RIGHTWARDS ARROW..DOUBLE CURLY LOOP +27C0..27C4;AL # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET +27C5;OP # Ps LEFT S-SHAPED BAG DELIMITER +27C6;CL # Pe RIGHT S-SHAPED BAG DELIMITER +27C7..27E5;AL # Sm [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK +27E6;OP # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET +27E7;CL # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET +27E8;OP # Ps MATHEMATICAL LEFT ANGLE BRACKET +27E9;CL # Pe MATHEMATICAL RIGHT ANGLE BRACKET +27EA;OP # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET +27EB;CL # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET +27EC;OP # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET +27ED;CL # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET +27EE;OP # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS +27EF;CL # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS +27F0..27FF;AL # Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW +2800..28FF;AL # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678 +2900..297F;AL # Sm [128] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..DOWN FISH TAIL +2980..2982;AL # Sm [3] TRIPLE VERTICAL BAR DELIMITER..Z NOTATION TYPE COLON +2983;OP # Ps LEFT WHITE CURLY BRACKET +2984;CL # Pe RIGHT WHITE CURLY BRACKET +2985;OP # Ps LEFT WHITE PARENTHESIS +2986;CL # Pe RIGHT WHITE PARENTHESIS +2987;OP # Ps Z NOTATION LEFT IMAGE BRACKET +2988;CL # Pe Z NOTATION RIGHT IMAGE BRACKET +2989;OP # Ps Z NOTATION LEFT BINDING BRACKET +298A;CL # Pe Z NOTATION RIGHT BINDING BRACKET +298B;OP # Ps LEFT SQUARE BRACKET WITH UNDERBAR +298C;CL # Pe RIGHT SQUARE BRACKET WITH UNDERBAR +298D;OP # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER +298E;CL # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +298F;OP # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +2990;CL # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER +2991;OP # Ps LEFT ANGLE BRACKET WITH DOT +2992;CL # Pe RIGHT ANGLE BRACKET WITH DOT +2993;OP # Ps LEFT ARC LESS-THAN BRACKET +2994;CL # Pe RIGHT ARC GREATER-THAN BRACKET +2995;OP # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET +2996;CL # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET +2997;OP # Ps LEFT BLACK TORTOISE SHELL BRACKET +2998;CL # Pe RIGHT BLACK TORTOISE SHELL BRACKET +2999..29D7;AL # Sm [63] DOTTED FENCE..BLACK HOURGLASS +29D8;OP # Ps LEFT WIGGLY FENCE +29D9;CL # Pe RIGHT WIGGLY FENCE +29DA;OP # Ps LEFT DOUBLE WIGGLY FENCE +29DB;CL # Pe RIGHT DOUBLE WIGGLY FENCE +29DC..29FB;AL # Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS +29FC;OP # Ps LEFT-POINTING CURVED ANGLE BRACKET +29FD;CL # Pe RIGHT-POINTING CURVED ANGLE BRACKET +29FE..29FF;AL # Sm [2] TINY..MINY +2A00..2AFF;AL # Sm [256] N-ARY CIRCLED DOT OPERATOR..N-ARY WHITE VERTICAL BAR +2B00..2B2F;AL # So [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE +2B30..2B44;AL # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET +2B45..2B46;AL # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW +2B47..2B4C;AL # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR +2B4D..2B54;AL # So [8] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..WHITE RIGHT-POINTING PENTAGON +2B55..2B59;AI # So [5] HEAVY LARGE CIRCLE..HEAVY CIRCLED SALTIRE +2B5A..2B73;AL # So [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR +2B76..2B95;AL # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW +2B97..2BFF;AL # So [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL +2C00..2C2E;AL # Lu [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +2C30..2C5E;AL # Ll [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE +2C60..2C7B;AL # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E +2C7C..2C7D;AL # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V +2C7E..2C7F;AL # Lu [2] LATIN CAPITAL LETTER S WITH SWASH TAIL..LATIN CAPITAL LETTER Z WITH SWASH TAIL +2C80..2CE4;AL # L& [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI +2CE5..2CEA;AL # So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA +2CEB..2CEE;AL # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA +2CEF..2CF1;CM # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS +2CF2..2CF3;AL # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI +2CF9;EX # Po COPTIC OLD NUBIAN FULL STOP +2CFA..2CFC;BA # Po [3] COPTIC OLD NUBIAN DIRECT QUESTION MARK..COPTIC OLD NUBIAN VERSE DIVIDER +2CFD;AL # No COPTIC FRACTION ONE HALF +2CFE;EX # Po COPTIC FULL STOP +2CFF;BA # Po COPTIC MORPHOLOGICAL DIVIDER +2D00..2D25;AL # Ll [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE +2D27;AL # Ll GEORGIAN SMALL LETTER YN +2D2D;AL # Ll GEORGIAN SMALL LETTER AEN +2D30..2D67;AL # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO +2D6F;AL # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK +2D70;BA # Po TIFINAGH SEPARATOR MARK +2D7F;CM # Mn TIFINAGH CONSONANT JOINER +2D80..2D96;AL # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE +2DA0..2DA6;AL # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO +2DA8..2DAE;AL # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO +2DB0..2DB6;AL # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO +2DB8..2DBE;AL # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO +2DC0..2DC6;AL # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO +2DC8..2DCE;AL # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO +2DD0..2DD6;AL # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO +2DD8..2DDE;AL # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO +2DE0..2DFF;CM # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS +2E00..2E01;QU # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER +2E02;QU # Pi LEFT SUBSTITUTION BRACKET +2E03;QU # Pf RIGHT SUBSTITUTION BRACKET +2E04;QU # Pi LEFT DOTTED SUBSTITUTION BRACKET +2E05;QU # Pf RIGHT DOTTED SUBSTITUTION BRACKET +2E06..2E08;QU # Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER +2E09;QU # Pi LEFT TRANSPOSITION BRACKET +2E0A;QU # Pf RIGHT TRANSPOSITION BRACKET +2E0B;QU # Po RAISED SQUARE +2E0C;QU # Pi LEFT RAISED OMISSION BRACKET +2E0D;QU # Pf RIGHT RAISED OMISSION BRACKET +2E0E..2E15;BA # Po [8] EDITORIAL CORONIS..UPWARDS ANCORA +2E16;AL # Po DOTTED RIGHT-POINTING ANGLE +2E17;BA # Pd DOUBLE OBLIQUE HYPHEN +2E18;OP # Po INVERTED INTERROBANG +2E19;BA # Po PALM BRANCH +2E1A;AL # Pd HYPHEN WITH DIAERESIS +2E1B;AL # Po TILDE WITH RING ABOVE +2E1C;QU # Pi LEFT LOW PARAPHRASE BRACKET +2E1D;QU # Pf RIGHT LOW PARAPHRASE BRACKET +2E1E..2E1F;AL # Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW +2E20;QU # Pi LEFT VERTICAL BAR WITH QUILL +2E21;QU # Pf RIGHT VERTICAL BAR WITH QUILL +2E22;OP # Ps TOP LEFT HALF BRACKET +2E23;CL # Pe TOP RIGHT HALF BRACKET +2E24;OP # Ps BOTTOM LEFT HALF BRACKET +2E25;CL # Pe BOTTOM RIGHT HALF BRACKET +2E26;OP # Ps LEFT SIDEWAYS U BRACKET +2E27;CL # Pe RIGHT SIDEWAYS U BRACKET +2E28;OP # Ps LEFT DOUBLE PARENTHESIS +2E29;CL # Pe RIGHT DOUBLE PARENTHESIS +2E2A..2E2D;BA # Po [4] TWO DOTS OVER ONE DOT PUNCTUATION..FIVE DOT MARK +2E2E;EX # Po REVERSED QUESTION MARK +2E2F;AL # Lm VERTICAL TILDE +2E30..2E31;BA # Po [2] RING POINT..WORD SEPARATOR MIDDLE DOT +2E32;AL # Po TURNED COMMA +2E33..2E34;BA # Po [2] RAISED DOT..RAISED COMMA +2E35..2E39;AL # Po [5] TURNED SEMICOLON..TOP HALF SECTION SIGN +2E3A..2E3B;B2 # Pd [2] TWO-EM DASH..THREE-EM DASH +2E3C..2E3E;BA # Po [3] STENOGRAPHIC FULL STOP..WIGGLY VERTICAL LINE +2E3F;AL # Po CAPITULUM +2E40;BA # Pd DOUBLE HYPHEN +2E41;BA # Po REVERSED COMMA +2E42;OP # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E4A;BA # Po [8] DASH WITH LEFT UPTURN..DOTTED SOLIDUS +2E4B;AL # Po TRIPLE DAGGER +2E4C;BA # Po MEDIEVAL COMMA +2E4D;AL # Po PARAGRAPHUS MARK +2E4E..2E4F;BA # Po [2] PUNCTUS ELEVATUS MARK..CORNISH VERSE DIVIDER +2E50..2E51;AL # So [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR +2E52;AL # Po TIRONIAN SIGN CAPITAL ET +2E80..2E99;ID # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP +2E9B..2EF3;ID # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE +2F00..2FD5;ID # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE +2FF0..2FFB;ID # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID +3000;BA # Zs IDEOGRAPHIC SPACE +3001..3002;CL # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP +3003;ID # Po DITTO MARK +3004;ID # So JAPANESE INDUSTRIAL STANDARD SYMBOL +3005;NS # Lm IDEOGRAPHIC ITERATION MARK +3006;ID # Lo IDEOGRAPHIC CLOSING MARK +3007;ID # Nl IDEOGRAPHIC NUMBER ZERO +3008;OP # Ps LEFT ANGLE BRACKET +3009;CL # Pe RIGHT ANGLE BRACKET +300A;OP # Ps LEFT DOUBLE ANGLE BRACKET +300B;CL # Pe RIGHT DOUBLE ANGLE BRACKET +300C;OP # Ps LEFT CORNER BRACKET +300D;CL # Pe RIGHT CORNER BRACKET +300E;OP # Ps LEFT WHITE CORNER BRACKET +300F;CL # Pe RIGHT WHITE CORNER BRACKET +3010;OP # Ps LEFT BLACK LENTICULAR BRACKET +3011;CL # Pe RIGHT BLACK LENTICULAR BRACKET +3012..3013;ID # So [2] POSTAL MARK..GETA MARK +3014;OP # Ps LEFT TORTOISE SHELL BRACKET +3015;CL # Pe RIGHT TORTOISE SHELL BRACKET +3016;OP # Ps LEFT WHITE LENTICULAR BRACKET +3017;CL # Pe RIGHT WHITE LENTICULAR BRACKET +3018;OP # Ps LEFT WHITE TORTOISE SHELL BRACKET +3019;CL # Pe RIGHT WHITE TORTOISE SHELL BRACKET +301A;OP # Ps LEFT WHITE SQUARE BRACKET +301B;CL # Pe RIGHT WHITE SQUARE BRACKET +301C;NS # Pd WAVE DASH +301D;OP # Ps REVERSED DOUBLE PRIME QUOTATION MARK +301E..301F;CL # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK +3020;ID # So POSTAL MARK FACE +3021..3029;ID # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE +302A..302D;CM # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK +302E..302F;CM # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK +3030;ID # Pd WAVY DASH +3031..3034;ID # Lm [4] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF +3035;CM # Lm VERTICAL KANA REPEAT MARK LOWER HALF +3036..3037;ID # So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL +3038..303A;ID # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY +303B;NS # Lm VERTICAL IDEOGRAPHIC ITERATION MARK +303C;NS # Lo MASU MARK +303D;ID # Po PART ALTERNATION MARK +303E..303F;ID # So [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE +3041;CJ # Lo HIRAGANA LETTER SMALL A +3042;ID # Lo HIRAGANA LETTER A +3043;CJ # Lo HIRAGANA LETTER SMALL I +3044;ID # Lo HIRAGANA LETTER I +3045;CJ # Lo HIRAGANA LETTER SMALL U +3046;ID # Lo HIRAGANA LETTER U +3047;CJ # Lo HIRAGANA LETTER SMALL E +3048;ID # Lo HIRAGANA LETTER E +3049;CJ # Lo HIRAGANA LETTER SMALL O +304A..3062;ID # Lo [25] HIRAGANA LETTER O..HIRAGANA LETTER DI +3063;CJ # Lo HIRAGANA LETTER SMALL TU +3064..3082;ID # Lo [31] HIRAGANA LETTER TU..HIRAGANA LETTER MO +3083;CJ # Lo HIRAGANA LETTER SMALL YA +3084;ID # Lo HIRAGANA LETTER YA +3085;CJ # Lo HIRAGANA LETTER SMALL YU +3086;ID # Lo HIRAGANA LETTER YU +3087;CJ # Lo HIRAGANA LETTER SMALL YO +3088..308D;ID # Lo [6] HIRAGANA LETTER YO..HIRAGANA LETTER RO +308E;CJ # Lo HIRAGANA LETTER SMALL WA +308F..3094;ID # Lo [6] HIRAGANA LETTER WA..HIRAGANA LETTER VU +3095..3096;CJ # Lo [2] HIRAGANA LETTER SMALL KA..HIRAGANA LETTER SMALL KE +3099..309A;CM # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309B..309C;NS # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309D..309E;NS # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK +309F;ID # Lo HIRAGANA DIGRAPH YORI +30A0;NS # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN +30A1;CJ # Lo KATAKANA LETTER SMALL A +30A2;ID # Lo KATAKANA LETTER A +30A3;CJ # Lo KATAKANA LETTER SMALL I +30A4;ID # Lo KATAKANA LETTER I +30A5;CJ # Lo KATAKANA LETTER SMALL U +30A6;ID # Lo KATAKANA LETTER U +30A7;CJ # Lo KATAKANA LETTER SMALL E +30A8;ID # Lo KATAKANA LETTER E +30A9;CJ # Lo KATAKANA LETTER SMALL O +30AA..30C2;ID # Lo [25] KATAKANA LETTER O..KATAKANA LETTER DI +30C3;CJ # Lo KATAKANA LETTER SMALL TU +30C4..30E2;ID # Lo [31] KATAKANA LETTER TU..KATAKANA LETTER MO +30E3;CJ # Lo KATAKANA LETTER SMALL YA +30E4;ID # Lo KATAKANA LETTER YA +30E5;CJ # Lo KATAKANA LETTER SMALL YU +30E6;ID # Lo KATAKANA LETTER YU +30E7;CJ # Lo KATAKANA LETTER SMALL YO +30E8..30ED;ID # Lo [6] KATAKANA LETTER YO..KATAKANA LETTER RO +30EE;CJ # Lo KATAKANA LETTER SMALL WA +30EF..30F4;ID # Lo [6] KATAKANA LETTER WA..KATAKANA LETTER VU +30F5..30F6;CJ # Lo [2] KATAKANA LETTER SMALL KA..KATAKANA LETTER SMALL KE +30F7..30FA;ID # Lo [4] KATAKANA LETTER VA..KATAKANA LETTER VO +30FB;NS # Po KATAKANA MIDDLE DOT +30FC;CJ # Lm KATAKANA-HIRAGANA PROLONGED SOUND MARK +30FD..30FE;NS # Lm [2] KATAKANA ITERATION MARK..KATAKANA VOICED ITERATION MARK +30FF;ID # Lo KATAKANA DIGRAPH KOTO +3105..312F;ID # Lo [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN +3131..318E;ID # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE +3190..3191;ID # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK +3192..3195;ID # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK +3196..319F;ID # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK +31A0..31BF;ID # Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH +31C0..31E3;ID # So [36] CJK STROKE T..CJK STROKE Q +31F0..31FF;CJ # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO +3200..321E;ID # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU +3220..3229;ID # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN +322A..3247;ID # So [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO +3248..324F;AI # No [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE +3250;ID # So PARTNERSHIP SIGN +3251..325F;ID # No [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE +3260..327F;ID # So [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL +3280..3289;ID # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN +328A..32B0;ID # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT +32B1..32BF;ID # No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY +32C0..32FF;ID # So [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA +3300..33FF;ID # So [256] SQUARE APAATO..SQUARE GAL +3400..4DBF;ID # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF +4DC0..4DFF;AL # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION +4E00..9FFC;ID # Lo [20989] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFC +9FFD..9FFF;ID # Cn [3] .. +A000..A014;ID # Lo [21] YI SYLLABLE IT..YI SYLLABLE E +A015;NS # Lm YI SYLLABLE WU +A016..A48C;ID # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR +A490..A4C6;ID # So [55] YI RADICAL QOT..YI RADICAL KE +A4D0..A4F7;AL # Lo [40] LISU LETTER BA..LISU LETTER OE +A4F8..A4FD;AL # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU +A4FE..A4FF;BA # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP +A500..A60B;AL # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG +A60C;AL # Lm VAI SYLLABLE LENGTHENER +A60D;BA # Po VAI COMMA +A60E;EX # Po VAI FULL STOP +A60F;BA # Po VAI QUESTION MARK +A610..A61F;AL # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG +A620..A629;NU # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE +A62A..A62B;AL # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO +A640..A66D;AL # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O +A66E;AL # Lo CYRILLIC LETTER MULTIOCULAR O +A66F;CM # Mn COMBINING CYRILLIC VZMET +A670..A672;CM # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN +A673;AL # Po SLAVONIC ASTERISK +A674..A67D;CM # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK +A67E;AL # Po CYRILLIC KAVYKA +A67F;AL # Lm CYRILLIC PAYEROK +A680..A69B;AL # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O +A69C..A69D;AL # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN +A69E..A69F;CM # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E +A6A0..A6E5;AL # Lo [70] BAMUM LETTER A..BAMUM LETTER KI +A6E6..A6EF;AL # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM +A6F0..A6F1;CM # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS +A6F2;AL # Po BAMUM NJAEMLI +A6F3..A6F7;BA # Po [5] BAMUM FULL STOP..BAMUM QUESTION MARK +A700..A716;AL # Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR +A717..A71F;AL # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK +A720..A721;AL # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE +A722..A76F;AL # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON +A770;AL # Lm MODIFIER LETTER US +A771..A787;AL # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T +A788;AL # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT +A789..A78A;AL # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN +A78B..A78E;AL # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT +A78F;AL # Lo LATIN LETTER SINOLOGICAL DOT +A790..A7BF;AL # L& [48] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER GLOTTAL U +A7C2..A7CA;AL # L& [9] LATIN CAPITAL LETTER ANGLICANA W..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7F5..A7F6;AL # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H +A7F7;AL # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I +A7F8..A7F9;AL # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE +A7FA;AL # Ll LATIN LETTER SMALL CAPITAL TURNED M +A7FB..A7FF;AL # Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M +A800..A801;AL # Lo [2] SYLOTI NAGRI LETTER A..SYLOTI NAGRI LETTER I +A802;CM # Mn SYLOTI NAGRI SIGN DVISVARA +A803..A805;AL # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O +A806;CM # Mn SYLOTI NAGRI SIGN HASANTA +A807..A80A;AL # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO +A80B;CM # Mn SYLOTI NAGRI SIGN ANUSVARA +A80C..A822;AL # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO +A823..A824;CM # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I +A825..A826;CM # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E +A827;CM # Mc SYLOTI NAGRI VOWEL SIGN OO +A828..A82B;AL # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4 +A82C;CM # Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA +A830..A835;AL # No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS +A836..A837;AL # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK +A838;PO # Sc NORTH INDIC RUPEE MARK +A839;AL # So NORTH INDIC QUANTITY MARK +A840..A873;AL # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU +A874..A875;BB # Po [2] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA DOUBLE HEAD MARK +A876..A877;EX # Po [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD +A880..A881;CM # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA +A882..A8B3;AL # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA +A8B4..A8C3;CM # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU +A8C4..A8C5;CM # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU +A8CE..A8CF;BA # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA +A8D0..A8D9;NU # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE +A8E0..A8F1;CM # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA +A8F2..A8F7;AL # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA +A8F8..A8FA;AL # Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET +A8FB;AL # Lo DEVANAGARI HEADSTROKE +A8FC;BB # Po DEVANAGARI SIGN SIDDHAM +A8FD..A8FE;AL # Lo [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY +A8FF;CM # Mn DEVANAGARI VOWEL SIGN AY +A900..A909;NU # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE +A90A..A925;AL # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO +A926..A92D;CM # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU +A92E..A92F;BA # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA +A930..A946;AL # Lo [23] REJANG LETTER KA..REJANG LETTER A +A947..A951;CM # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R +A952..A953;CM # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA +A95F;AL # Po REJANG SECTION MARK +A960..A97C;JL # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH +A980..A982;CM # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR +A983;CM # Mc JAVANESE SIGN WIGNYAN +A984..A9B2;AL # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA +A9B3;CM # Mn JAVANESE SIGN CECAK TELU +A9B4..A9B5;CM # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG +A9B6..A9B9;CM # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT +A9BA..A9BB;CM # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE +A9BC..A9BD;CM # Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET +A9BE..A9C0;CM # Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON +A9C1..A9C6;AL # Po [6] JAVANESE LEFT RERENGGAN..JAVANESE PADA WINDU +A9C7..A9C9;BA # Po [3] JAVANESE PADA PANGKAT..JAVANESE PADA LUNGSI +A9CA..A9CD;AL # Po [4] JAVANESE PADA ADEG..JAVANESE TURNED PADA PISELEH +A9CF;AL # Lm JAVANESE PANGRANGKEP +A9D0..A9D9;NU # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE +A9DE..A9DF;AL # Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN +A9E0..A9E4;SA # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA +A9E5;SA # Mn MYANMAR SIGN SHAN SAW +A9E6;SA # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION +A9E7..A9EF;SA # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA +A9F0..A9F9;NU # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE +A9FA..A9FE;SA # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA +AA00..AA28;AL # Lo [41] CHAM LETTER A..CHAM LETTER HA +AA29..AA2E;CM # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE +AA2F..AA30;CM # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI +AA31..AA32;CM # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE +AA33..AA34;CM # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA +AA35..AA36;CM # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA +AA40..AA42;AL # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG +AA43;CM # Mn CHAM CONSONANT SIGN FINAL NG +AA44..AA4B;AL # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS +AA4C;CM # Mn CHAM CONSONANT SIGN FINAL M +AA4D;CM # Mc CHAM CONSONANT SIGN FINAL H +AA50..AA59;NU # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE +AA5C;AL # Po CHAM PUNCTUATION SPIRAL +AA5D..AA5F;BA # Po [3] CHAM PUNCTUATION DANDA..CHAM PUNCTUATION TRIPLE DANDA +AA60..AA6F;SA # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA +AA70;SA # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION +AA71..AA76;SA # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM +AA77..AA79;SA # So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO +AA7A;SA # Lo MYANMAR LETTER AITON RA +AA7B;SA # Mc MYANMAR SIGN PAO KAREN TONE +AA7C;SA # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D;SA # Mc MYANMAR SIGN TAI LAING TONE-5 +AA7E..AA7F;SA # Lo [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA +AA80..AAAF;SA # Lo [48] TAI VIET LETTER LOW KO..TAI VIET LETTER HIGH O +AAB0;SA # Mn TAI VIET MAI KANG +AAB1;SA # Lo TAI VIET VOWEL AA +AAB2..AAB4;SA # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U +AAB5..AAB6;SA # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O +AAB7..AAB8;SA # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA +AAB9..AABD;SA # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN +AABE..AABF;SA # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK +AAC0;SA # Lo TAI VIET TONE MAI NUENG +AAC1;SA # Mn TAI VIET TONE MAI THO +AAC2;SA # Lo TAI VIET TONE MAI SONG +AADB..AADC;SA # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG +AADD;SA # Lm TAI VIET SYMBOL SAM +AADE..AADF;SA # Po [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI +AAE0..AAEA;AL # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA +AAEB;CM # Mc MEETEI MAYEK VOWEL SIGN II +AAEC..AAED;CM # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI +AAEE..AAEF;CM # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU +AAF0..AAF1;BA # Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM +AAF2;AL # Lo MEETEI MAYEK ANJI +AAF3..AAF4;AL # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK +AAF5;CM # Mc MEETEI MAYEK VOWEL SIGN VISARGA +AAF6;CM # Mn MEETEI MAYEK VIRAMA +AB01..AB06;AL # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO +AB09..AB0E;AL # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO +AB11..AB16;AL # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO +AB20..AB26;AL # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO +AB28..AB2E;AL # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO +AB30..AB5A;AL # Ll [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG +AB5B;AL # Sk MODIFIER BREVE WITH INVERTED BREVE +AB5C..AB5F;AL # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK +AB60..AB68;AL # Ll [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE +AB69;AL # Lm MODIFIER LETTER SMALL TURNED W +AB6A..AB6B;AL # Sk [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK +AB70..ABBF;AL # Ll [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA +ABC0..ABE2;AL # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM +ABE3..ABE4;CM # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP +ABE5;CM # Mn MEETEI MAYEK VOWEL SIGN ANAP +ABE6..ABE7;CM # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP +ABE8;CM # Mn MEETEI MAYEK VOWEL SIGN UNAP +ABE9..ABEA;CM # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG +ABEB;BA # Po MEETEI MAYEK CHEIKHEI +ABEC;CM # Mc MEETEI MAYEK LUM IYEK +ABED;CM # Mn MEETEI MAYEK APUN IYEK +ABF0..ABF9;NU # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE +AC00;H2 # Lo HANGUL SYLLABLE GA +AC01..AC1B;H3 # Lo [27] HANGUL SYLLABLE GAG..HANGUL SYLLABLE GAH +AC1C;H2 # Lo HANGUL SYLLABLE GAE +AC1D..AC37;H3 # Lo [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH +AC38;H2 # Lo HANGUL SYLLABLE GYA +AC39..AC53;H3 # Lo [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH +AC54;H2 # Lo HANGUL SYLLABLE GYAE +AC55..AC6F;H3 # Lo [27] HANGUL SYLLABLE GYAEG..HANGUL SYLLABLE GYAEH +AC70;H2 # Lo HANGUL SYLLABLE GEO +AC71..AC8B;H3 # Lo [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH +AC8C;H2 # Lo HANGUL SYLLABLE GE +AC8D..ACA7;H3 # Lo [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE GEH +ACA8;H2 # Lo HANGUL SYLLABLE GYEO +ACA9..ACC3;H3 # Lo [27] HANGUL SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH +ACC4;H2 # Lo HANGUL SYLLABLE GYE +ACC5..ACDF;H3 # Lo [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH +ACE0;H2 # Lo HANGUL SYLLABLE GO +ACE1..ACFB;H3 # Lo [27] HANGUL SYLLABLE GOG..HANGUL SYLLABLE GOH +ACFC;H2 # Lo HANGUL SYLLABLE GWA +ACFD..AD17;H3 # Lo [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH +AD18;H2 # Lo HANGUL SYLLABLE GWAE +AD19..AD33;H3 # Lo [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH +AD34;H2 # Lo HANGUL SYLLABLE GOE +AD35..AD4F;H3 # Lo [27] HANGUL SYLLABLE GOEG..HANGUL SYLLABLE GOEH +AD50;H2 # Lo HANGUL SYLLABLE GYO +AD51..AD6B;H3 # Lo [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH +AD6C;H2 # Lo HANGUL SYLLABLE GU +AD6D..AD87;H3 # Lo [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH +AD88;H2 # Lo HANGUL SYLLABLE GWEO +AD89..ADA3;H3 # Lo [27] HANGUL SYLLABLE GWEOG..HANGUL SYLLABLE GWEOH +ADA4;H2 # Lo HANGUL SYLLABLE GWE +ADA5..ADBF;H3 # Lo [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH +ADC0;H2 # Lo HANGUL SYLLABLE GWI +ADC1..ADDB;H3 # Lo [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE GWIH +ADDC;H2 # Lo HANGUL SYLLABLE GYU +ADDD..ADF7;H3 # Lo [27] HANGUL SYLLABLE GYUG..HANGUL SYLLABLE GYUH +ADF8;H2 # Lo HANGUL SYLLABLE GEU +ADF9..AE13;H3 # Lo [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH +AE14;H2 # Lo HANGUL SYLLABLE GYI +AE15..AE2F;H3 # Lo [27] HANGUL SYLLABLE GYIG..HANGUL SYLLABLE GYIH +AE30;H2 # Lo HANGUL SYLLABLE GI +AE31..AE4B;H3 # Lo [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH +AE4C;H2 # Lo HANGUL SYLLABLE GGA +AE4D..AE67;H3 # Lo [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH +AE68;H2 # Lo HANGUL SYLLABLE GGAE +AE69..AE83;H3 # Lo [27] HANGUL SYLLABLE GGAEG..HANGUL SYLLABLE GGAEH +AE84;H2 # Lo HANGUL SYLLABLE GGYA +AE85..AE9F;H3 # Lo [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH +AEA0;H2 # Lo HANGUL SYLLABLE GGYAE +AEA1..AEBB;H3 # Lo [27] HANGUL SYLLABLE GGYAEG..HANGUL SYLLABLE GGYAEH +AEBC;H2 # Lo HANGUL SYLLABLE GGEO +AEBD..AED7;H3 # Lo [27] HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH +AED8;H2 # Lo HANGUL SYLLABLE GGE +AED9..AEF3;H3 # Lo [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH +AEF4;H2 # Lo HANGUL SYLLABLE GGYEO +AEF5..AF0F;H3 # Lo [27] HANGUL SYLLABLE GGYEOG..HANGUL SYLLABLE GGYEOH +AF10;H2 # Lo HANGUL SYLLABLE GGYE +AF11..AF2B;H3 # Lo [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH +AF2C;H2 # Lo HANGUL SYLLABLE GGO +AF2D..AF47;H3 # Lo [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE GGOH +AF48;H2 # Lo HANGUL SYLLABLE GGWA +AF49..AF63;H3 # Lo [27] HANGUL SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH +AF64;H2 # Lo HANGUL SYLLABLE GGWAE +AF65..AF7F;H3 # Lo [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH +AF80;H2 # Lo HANGUL SYLLABLE GGOE +AF81..AF9B;H3 # Lo [27] HANGUL SYLLABLE GGOEG..HANGUL SYLLABLE GGOEH +AF9C;H2 # Lo HANGUL SYLLABLE GGYO +AF9D..AFB7;H3 # Lo [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH +AFB8;H2 # Lo HANGUL SYLLABLE GGU +AFB9..AFD3;H3 # Lo [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE GGUH +AFD4;H2 # Lo HANGUL SYLLABLE GGWEO +AFD5..AFEF;H3 # Lo [27] HANGUL SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH +AFF0;H2 # Lo HANGUL SYLLABLE GGWE +AFF1..B00B;H3 # Lo [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH +B00C;H2 # Lo HANGUL SYLLABLE GGWI +B00D..B027;H3 # Lo [27] HANGUL SYLLABLE GGWIG..HANGUL SYLLABLE GGWIH +B028;H2 # Lo HANGUL SYLLABLE GGYU +B029..B043;H3 # Lo [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH +B044;H2 # Lo HANGUL SYLLABLE GGEU +B045..B05F;H3 # Lo [27] HANGUL SYLLABLE GGEUG..HANGUL SYLLABLE GGEUH +B060;H2 # Lo HANGUL SYLLABLE GGYI +B061..B07B;H3 # Lo [27] HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH +B07C;H2 # Lo HANGUL SYLLABLE GGI +B07D..B097;H3 # Lo [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH +B098;H2 # Lo HANGUL SYLLABLE NA +B099..B0B3;H3 # Lo [27] HANGUL SYLLABLE NAG..HANGUL SYLLABLE NAH +B0B4;H2 # Lo HANGUL SYLLABLE NAE +B0B5..B0CF;H3 # Lo [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH +B0D0;H2 # Lo HANGUL SYLLABLE NYA +B0D1..B0EB;H3 # Lo [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH +B0EC;H2 # Lo HANGUL SYLLABLE NYAE +B0ED..B107;H3 # Lo [27] HANGUL SYLLABLE NYAEG..HANGUL SYLLABLE NYAEH +B108;H2 # Lo HANGUL SYLLABLE NEO +B109..B123;H3 # Lo [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH +B124;H2 # Lo HANGUL SYLLABLE NE +B125..B13F;H3 # Lo [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE NEH +B140;H2 # Lo HANGUL SYLLABLE NYEO +B141..B15B;H3 # Lo [27] HANGUL SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH +B15C;H2 # Lo HANGUL SYLLABLE NYE +B15D..B177;H3 # Lo [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH +B178;H2 # Lo HANGUL SYLLABLE NO +B179..B193;H3 # Lo [27] HANGUL SYLLABLE NOG..HANGUL SYLLABLE NOH +B194;H2 # Lo HANGUL SYLLABLE NWA +B195..B1AF;H3 # Lo [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH +B1B0;H2 # Lo HANGUL SYLLABLE NWAE +B1B1..B1CB;H3 # Lo [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH +B1CC;H2 # Lo HANGUL SYLLABLE NOE +B1CD..B1E7;H3 # Lo [27] HANGUL SYLLABLE NOEG..HANGUL SYLLABLE NOEH +B1E8;H2 # Lo HANGUL SYLLABLE NYO +B1E9..B203;H3 # Lo [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH +B204;H2 # Lo HANGUL SYLLABLE NU +B205..B21F;H3 # Lo [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH +B220;H2 # Lo HANGUL SYLLABLE NWEO +B221..B23B;H3 # Lo [27] HANGUL SYLLABLE NWEOG..HANGUL SYLLABLE NWEOH +B23C;H2 # Lo HANGUL SYLLABLE NWE +B23D..B257;H3 # Lo [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH +B258;H2 # Lo HANGUL SYLLABLE NWI +B259..B273;H3 # Lo [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE NWIH +B274;H2 # Lo HANGUL SYLLABLE NYU +B275..B28F;H3 # Lo [27] HANGUL SYLLABLE NYUG..HANGUL SYLLABLE NYUH +B290;H2 # Lo HANGUL SYLLABLE NEU +B291..B2AB;H3 # Lo [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH +B2AC;H2 # Lo HANGUL SYLLABLE NYI +B2AD..B2C7;H3 # Lo [27] HANGUL SYLLABLE NYIG..HANGUL SYLLABLE NYIH +B2C8;H2 # Lo HANGUL SYLLABLE NI +B2C9..B2E3;H3 # Lo [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH +B2E4;H2 # Lo HANGUL SYLLABLE DA +B2E5..B2FF;H3 # Lo [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH +B300;H2 # Lo HANGUL SYLLABLE DAE +B301..B31B;H3 # Lo [27] HANGUL SYLLABLE DAEG..HANGUL SYLLABLE DAEH +B31C;H2 # Lo HANGUL SYLLABLE DYA +B31D..B337;H3 # Lo [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH +B338;H2 # Lo HANGUL SYLLABLE DYAE +B339..B353;H3 # Lo [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE DYAEH +B354;H2 # Lo HANGUL SYLLABLE DEO +B355..B36F;H3 # Lo [27] HANGUL SYLLABLE DEOG..HANGUL SYLLABLE DEOH +B370;H2 # Lo HANGUL SYLLABLE DE +B371..B38B;H3 # Lo [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH +B38C;H2 # Lo HANGUL SYLLABLE DYEO +B38D..B3A7;H3 # Lo [27] HANGUL SYLLABLE DYEOG..HANGUL SYLLABLE DYEOH +B3A8;H2 # Lo HANGUL SYLLABLE DYE +B3A9..B3C3;H3 # Lo [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH +B3C4;H2 # Lo HANGUL SYLLABLE DO +B3C5..B3DF;H3 # Lo [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE DOH +B3E0;H2 # Lo HANGUL SYLLABLE DWA +B3E1..B3FB;H3 # Lo [27] HANGUL SYLLABLE DWAG..HANGUL SYLLABLE DWAH +B3FC;H2 # Lo HANGUL SYLLABLE DWAE +B3FD..B417;H3 # Lo [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH +B418;H2 # Lo HANGUL SYLLABLE DOE +B419..B433;H3 # Lo [27] HANGUL SYLLABLE DOEG..HANGUL SYLLABLE DOEH +B434;H2 # Lo HANGUL SYLLABLE DYO +B435..B44F;H3 # Lo [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH +B450;H2 # Lo HANGUL SYLLABLE DU +B451..B46B;H3 # Lo [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH +B46C;H2 # Lo HANGUL SYLLABLE DWEO +B46D..B487;H3 # Lo [27] HANGUL SYLLABLE DWEOG..HANGUL SYLLABLE DWEOH +B488;H2 # Lo HANGUL SYLLABLE DWE +B489..B4A3;H3 # Lo [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH +B4A4;H2 # Lo HANGUL SYLLABLE DWI +B4A5..B4BF;H3 # Lo [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE DWIH +B4C0;H2 # Lo HANGUL SYLLABLE DYU +B4C1..B4DB;H3 # Lo [27] HANGUL SYLLABLE DYUG..HANGUL SYLLABLE DYUH +B4DC;H2 # Lo HANGUL SYLLABLE DEU +B4DD..B4F7;H3 # Lo [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH +B4F8;H2 # Lo HANGUL SYLLABLE DYI +B4F9..B513;H3 # Lo [27] HANGUL SYLLABLE DYIG..HANGUL SYLLABLE DYIH +B514;H2 # Lo HANGUL SYLLABLE DI +B515..B52F;H3 # Lo [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH +B530;H2 # Lo HANGUL SYLLABLE DDA +B531..B54B;H3 # Lo [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH +B54C;H2 # Lo HANGUL SYLLABLE DDAE +B54D..B567;H3 # Lo [27] HANGUL SYLLABLE DDAEG..HANGUL SYLLABLE DDAEH +B568;H2 # Lo HANGUL SYLLABLE DDYA +B569..B583;H3 # Lo [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH +B584;H2 # Lo HANGUL SYLLABLE DDYAE +B585..B59F;H3 # Lo [27] HANGUL SYLLABLE DDYAEG..HANGUL SYLLABLE DDYAEH +B5A0;H2 # Lo HANGUL SYLLABLE DDEO +B5A1..B5BB;H3 # Lo [27] HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH +B5BC;H2 # Lo HANGUL SYLLABLE DDE +B5BD..B5D7;H3 # Lo [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH +B5D8;H2 # Lo HANGUL SYLLABLE DDYEO +B5D9..B5F3;H3 # Lo [27] HANGUL SYLLABLE DDYEOG..HANGUL SYLLABLE DDYEOH +B5F4;H2 # Lo HANGUL SYLLABLE DDYE +B5F5..B60F;H3 # Lo [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH +B610;H2 # Lo HANGUL SYLLABLE DDO +B611..B62B;H3 # Lo [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE DDOH +B62C;H2 # Lo HANGUL SYLLABLE DDWA +B62D..B647;H3 # Lo [27] HANGUL SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH +B648;H2 # Lo HANGUL SYLLABLE DDWAE +B649..B663;H3 # Lo [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH +B664;H2 # Lo HANGUL SYLLABLE DDOE +B665..B67F;H3 # Lo [27] HANGUL SYLLABLE DDOEG..HANGUL SYLLABLE DDOEH +B680;H2 # Lo HANGUL SYLLABLE DDYO +B681..B69B;H3 # Lo [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH +B69C;H2 # Lo HANGUL SYLLABLE DDU +B69D..B6B7;H3 # Lo [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE DDUH +B6B8;H2 # Lo HANGUL SYLLABLE DDWEO +B6B9..B6D3;H3 # Lo [27] HANGUL SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH +B6D4;H2 # Lo HANGUL SYLLABLE DDWE +B6D5..B6EF;H3 # Lo [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH +B6F0;H2 # Lo HANGUL SYLLABLE DDWI +B6F1..B70B;H3 # Lo [27] HANGUL SYLLABLE DDWIG..HANGUL SYLLABLE DDWIH +B70C;H2 # Lo HANGUL SYLLABLE DDYU +B70D..B727;H3 # Lo [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH +B728;H2 # Lo HANGUL SYLLABLE DDEU +B729..B743;H3 # Lo [27] HANGUL SYLLABLE DDEUG..HANGUL SYLLABLE DDEUH +B744;H2 # Lo HANGUL SYLLABLE DDYI +B745..B75F;H3 # Lo [27] HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH +B760;H2 # Lo HANGUL SYLLABLE DDI +B761..B77B;H3 # Lo [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH +B77C;H2 # Lo HANGUL SYLLABLE RA +B77D..B797;H3 # Lo [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAH +B798;H2 # Lo HANGUL SYLLABLE RAE +B799..B7B3;H3 # Lo [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH +B7B4;H2 # Lo HANGUL SYLLABLE RYA +B7B5..B7CF;H3 # Lo [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH +B7D0;H2 # Lo HANGUL SYLLABLE RYAE +B7D1..B7EB;H3 # Lo [27] HANGUL SYLLABLE RYAEG..HANGUL SYLLABLE RYAEH +B7EC;H2 # Lo HANGUL SYLLABLE REO +B7ED..B807;H3 # Lo [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH +B808;H2 # Lo HANGUL SYLLABLE RE +B809..B823;H3 # Lo [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE REH +B824;H2 # Lo HANGUL SYLLABLE RYEO +B825..B83F;H3 # Lo [27] HANGUL SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH +B840;H2 # Lo HANGUL SYLLABLE RYE +B841..B85B;H3 # Lo [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH +B85C;H2 # Lo HANGUL SYLLABLE RO +B85D..B877;H3 # Lo [27] HANGUL SYLLABLE ROG..HANGUL SYLLABLE ROH +B878;H2 # Lo HANGUL SYLLABLE RWA +B879..B893;H3 # Lo [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH +B894;H2 # Lo HANGUL SYLLABLE RWAE +B895..B8AF;H3 # Lo [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH +B8B0;H2 # Lo HANGUL SYLLABLE ROE +B8B1..B8CB;H3 # Lo [27] HANGUL SYLLABLE ROEG..HANGUL SYLLABLE ROEH +B8CC;H2 # Lo HANGUL SYLLABLE RYO +B8CD..B8E7;H3 # Lo [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH +B8E8;H2 # Lo HANGUL SYLLABLE RU +B8E9..B903;H3 # Lo [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH +B904;H2 # Lo HANGUL SYLLABLE RWEO +B905..B91F;H3 # Lo [27] HANGUL SYLLABLE RWEOG..HANGUL SYLLABLE RWEOH +B920;H2 # Lo HANGUL SYLLABLE RWE +B921..B93B;H3 # Lo [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH +B93C;H2 # Lo HANGUL SYLLABLE RWI +B93D..B957;H3 # Lo [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE RWIH +B958;H2 # Lo HANGUL SYLLABLE RYU +B959..B973;H3 # Lo [27] HANGUL SYLLABLE RYUG..HANGUL SYLLABLE RYUH +B974;H2 # Lo HANGUL SYLLABLE REU +B975..B98F;H3 # Lo [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH +B990;H2 # Lo HANGUL SYLLABLE RYI +B991..B9AB;H3 # Lo [27] HANGUL SYLLABLE RYIG..HANGUL SYLLABLE RYIH +B9AC;H2 # Lo HANGUL SYLLABLE RI +B9AD..B9C7;H3 # Lo [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH +B9C8;H2 # Lo HANGUL SYLLABLE MA +B9C9..B9E3;H3 # Lo [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH +B9E4;H2 # Lo HANGUL SYLLABLE MAE +B9E5..B9FF;H3 # Lo [27] HANGUL SYLLABLE MAEG..HANGUL SYLLABLE MAEH +BA00;H2 # Lo HANGUL SYLLABLE MYA +BA01..BA1B;H3 # Lo [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH +BA1C;H2 # Lo HANGUL SYLLABLE MYAE +BA1D..BA37;H3 # Lo [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE MYAEH +BA38;H2 # Lo HANGUL SYLLABLE MEO +BA39..BA53;H3 # Lo [27] HANGUL SYLLABLE MEOG..HANGUL SYLLABLE MEOH +BA54;H2 # Lo HANGUL SYLLABLE ME +BA55..BA6F;H3 # Lo [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH +BA70;H2 # Lo HANGUL SYLLABLE MYEO +BA71..BA8B;H3 # Lo [27] HANGUL SYLLABLE MYEOG..HANGUL SYLLABLE MYEOH +BA8C;H2 # Lo HANGUL SYLLABLE MYE +BA8D..BAA7;H3 # Lo [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH +BAA8;H2 # Lo HANGUL SYLLABLE MO +BAA9..BAC3;H3 # Lo [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE MOH +BAC4;H2 # Lo HANGUL SYLLABLE MWA +BAC5..BADF;H3 # Lo [27] HANGUL SYLLABLE MWAG..HANGUL SYLLABLE MWAH +BAE0;H2 # Lo HANGUL SYLLABLE MWAE +BAE1..BAFB;H3 # Lo [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH +BAFC;H2 # Lo HANGUL SYLLABLE MOE +BAFD..BB17;H3 # Lo [27] HANGUL SYLLABLE MOEG..HANGUL SYLLABLE MOEH +BB18;H2 # Lo HANGUL SYLLABLE MYO +BB19..BB33;H3 # Lo [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH +BB34;H2 # Lo HANGUL SYLLABLE MU +BB35..BB4F;H3 # Lo [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH +BB50;H2 # Lo HANGUL SYLLABLE MWEO +BB51..BB6B;H3 # Lo [27] HANGUL SYLLABLE MWEOG..HANGUL SYLLABLE MWEOH +BB6C;H2 # Lo HANGUL SYLLABLE MWE +BB6D..BB87;H3 # Lo [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH +BB88;H2 # Lo HANGUL SYLLABLE MWI +BB89..BBA3;H3 # Lo [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE MWIH +BBA4;H2 # Lo HANGUL SYLLABLE MYU +BBA5..BBBF;H3 # Lo [27] HANGUL SYLLABLE MYUG..HANGUL SYLLABLE MYUH +BBC0;H2 # Lo HANGUL SYLLABLE MEU +BBC1..BBDB;H3 # Lo [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH +BBDC;H2 # Lo HANGUL SYLLABLE MYI +BBDD..BBF7;H3 # Lo [27] HANGUL SYLLABLE MYIG..HANGUL SYLLABLE MYIH +BBF8;H2 # Lo HANGUL SYLLABLE MI +BBF9..BC13;H3 # Lo [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH +BC14;H2 # Lo HANGUL SYLLABLE BA +BC15..BC2F;H3 # Lo [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH +BC30;H2 # Lo HANGUL SYLLABLE BAE +BC31..BC4B;H3 # Lo [27] HANGUL SYLLABLE BAEG..HANGUL SYLLABLE BAEH +BC4C;H2 # Lo HANGUL SYLLABLE BYA +BC4D..BC67;H3 # Lo [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH +BC68;H2 # Lo HANGUL SYLLABLE BYAE +BC69..BC83;H3 # Lo [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE BYAEH +BC84;H2 # Lo HANGUL SYLLABLE BEO +BC85..BC9F;H3 # Lo [27] HANGUL SYLLABLE BEOG..HANGUL SYLLABLE BEOH +BCA0;H2 # Lo HANGUL SYLLABLE BE +BCA1..BCBB;H3 # Lo [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH +BCBC;H2 # Lo HANGUL SYLLABLE BYEO +BCBD..BCD7;H3 # Lo [27] HANGUL SYLLABLE BYEOG..HANGUL SYLLABLE BYEOH +BCD8;H2 # Lo HANGUL SYLLABLE BYE +BCD9..BCF3;H3 # Lo [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH +BCF4;H2 # Lo HANGUL SYLLABLE BO +BCF5..BD0F;H3 # Lo [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE BOH +BD10;H2 # Lo HANGUL SYLLABLE BWA +BD11..BD2B;H3 # Lo [27] HANGUL SYLLABLE BWAG..HANGUL SYLLABLE BWAH +BD2C;H2 # Lo HANGUL SYLLABLE BWAE +BD2D..BD47;H3 # Lo [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH +BD48;H2 # Lo HANGUL SYLLABLE BOE +BD49..BD63;H3 # Lo [27] HANGUL SYLLABLE BOEG..HANGUL SYLLABLE BOEH +BD64;H2 # Lo HANGUL SYLLABLE BYO +BD65..BD7F;H3 # Lo [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH +BD80;H2 # Lo HANGUL SYLLABLE BU +BD81..BD9B;H3 # Lo [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH +BD9C;H2 # Lo HANGUL SYLLABLE BWEO +BD9D..BDB7;H3 # Lo [27] HANGUL SYLLABLE BWEOG..HANGUL SYLLABLE BWEOH +BDB8;H2 # Lo HANGUL SYLLABLE BWE +BDB9..BDD3;H3 # Lo [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH +BDD4;H2 # Lo HANGUL SYLLABLE BWI +BDD5..BDEF;H3 # Lo [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE BWIH +BDF0;H2 # Lo HANGUL SYLLABLE BYU +BDF1..BE0B;H3 # Lo [27] HANGUL SYLLABLE BYUG..HANGUL SYLLABLE BYUH +BE0C;H2 # Lo HANGUL SYLLABLE BEU +BE0D..BE27;H3 # Lo [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH +BE28;H2 # Lo HANGUL SYLLABLE BYI +BE29..BE43;H3 # Lo [27] HANGUL SYLLABLE BYIG..HANGUL SYLLABLE BYIH +BE44;H2 # Lo HANGUL SYLLABLE BI +BE45..BE5F;H3 # Lo [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH +BE60;H2 # Lo HANGUL SYLLABLE BBA +BE61..BE7B;H3 # Lo [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH +BE7C;H2 # Lo HANGUL SYLLABLE BBAE +BE7D..BE97;H3 # Lo [27] HANGUL SYLLABLE BBAEG..HANGUL SYLLABLE BBAEH +BE98;H2 # Lo HANGUL SYLLABLE BBYA +BE99..BEB3;H3 # Lo [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH +BEB4;H2 # Lo HANGUL SYLLABLE BBYAE +BEB5..BECF;H3 # Lo [27] HANGUL SYLLABLE BBYAEG..HANGUL SYLLABLE BBYAEH +BED0;H2 # Lo HANGUL SYLLABLE BBEO +BED1..BEEB;H3 # Lo [27] HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH +BEEC;H2 # Lo HANGUL SYLLABLE BBE +BEED..BF07;H3 # Lo [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH +BF08;H2 # Lo HANGUL SYLLABLE BBYEO +BF09..BF23;H3 # Lo [27] HANGUL SYLLABLE BBYEOG..HANGUL SYLLABLE BBYEOH +BF24;H2 # Lo HANGUL SYLLABLE BBYE +BF25..BF3F;H3 # Lo [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH +BF40;H2 # Lo HANGUL SYLLABLE BBO +BF41..BF5B;H3 # Lo [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE BBOH +BF5C;H2 # Lo HANGUL SYLLABLE BBWA +BF5D..BF77;H3 # Lo [27] HANGUL SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH +BF78;H2 # Lo HANGUL SYLLABLE BBWAE +BF79..BF93;H3 # Lo [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH +BF94;H2 # Lo HANGUL SYLLABLE BBOE +BF95..BFAF;H3 # Lo [27] HANGUL SYLLABLE BBOEG..HANGUL SYLLABLE BBOEH +BFB0;H2 # Lo HANGUL SYLLABLE BBYO +BFB1..BFCB;H3 # Lo [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH +BFCC;H2 # Lo HANGUL SYLLABLE BBU +BFCD..BFE7;H3 # Lo [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE BBUH +BFE8;H2 # Lo HANGUL SYLLABLE BBWEO +BFE9..C003;H3 # Lo [27] HANGUL SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH +C004;H2 # Lo HANGUL SYLLABLE BBWE +C005..C01F;H3 # Lo [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH +C020;H2 # Lo HANGUL SYLLABLE BBWI +C021..C03B;H3 # Lo [27] HANGUL SYLLABLE BBWIG..HANGUL SYLLABLE BBWIH +C03C;H2 # Lo HANGUL SYLLABLE BBYU +C03D..C057;H3 # Lo [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH +C058;H2 # Lo HANGUL SYLLABLE BBEU +C059..C073;H3 # Lo [27] HANGUL SYLLABLE BBEUG..HANGUL SYLLABLE BBEUH +C074;H2 # Lo HANGUL SYLLABLE BBYI +C075..C08F;H3 # Lo [27] HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH +C090;H2 # Lo HANGUL SYLLABLE BBI +C091..C0AB;H3 # Lo [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH +C0AC;H2 # Lo HANGUL SYLLABLE SA +C0AD..C0C7;H3 # Lo [27] HANGUL SYLLABLE SAG..HANGUL SYLLABLE SAH +C0C8;H2 # Lo HANGUL SYLLABLE SAE +C0C9..C0E3;H3 # Lo [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH +C0E4;H2 # Lo HANGUL SYLLABLE SYA +C0E5..C0FF;H3 # Lo [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH +C100;H2 # Lo HANGUL SYLLABLE SYAE +C101..C11B;H3 # Lo [27] HANGUL SYLLABLE SYAEG..HANGUL SYLLABLE SYAEH +C11C;H2 # Lo HANGUL SYLLABLE SEO +C11D..C137;H3 # Lo [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH +C138;H2 # Lo HANGUL SYLLABLE SE +C139..C153;H3 # Lo [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE SEH +C154;H2 # Lo HANGUL SYLLABLE SYEO +C155..C16F;H3 # Lo [27] HANGUL SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH +C170;H2 # Lo HANGUL SYLLABLE SYE +C171..C18B;H3 # Lo [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH +C18C;H2 # Lo HANGUL SYLLABLE SO +C18D..C1A7;H3 # Lo [27] HANGUL SYLLABLE SOG..HANGUL SYLLABLE SOH +C1A8;H2 # Lo HANGUL SYLLABLE SWA +C1A9..C1C3;H3 # Lo [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH +C1C4;H2 # Lo HANGUL SYLLABLE SWAE +C1C5..C1DF;H3 # Lo [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH +C1E0;H2 # Lo HANGUL SYLLABLE SOE +C1E1..C1FB;H3 # Lo [27] HANGUL SYLLABLE SOEG..HANGUL SYLLABLE SOEH +C1FC;H2 # Lo HANGUL SYLLABLE SYO +C1FD..C217;H3 # Lo [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH +C218;H2 # Lo HANGUL SYLLABLE SU +C219..C233;H3 # Lo [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH +C234;H2 # Lo HANGUL SYLLABLE SWEO +C235..C24F;H3 # Lo [27] HANGUL SYLLABLE SWEOG..HANGUL SYLLABLE SWEOH +C250;H2 # Lo HANGUL SYLLABLE SWE +C251..C26B;H3 # Lo [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH +C26C;H2 # Lo HANGUL SYLLABLE SWI +C26D..C287;H3 # Lo [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE SWIH +C288;H2 # Lo HANGUL SYLLABLE SYU +C289..C2A3;H3 # Lo [27] HANGUL SYLLABLE SYUG..HANGUL SYLLABLE SYUH +C2A4;H2 # Lo HANGUL SYLLABLE SEU +C2A5..C2BF;H3 # Lo [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH +C2C0;H2 # Lo HANGUL SYLLABLE SYI +C2C1..C2DB;H3 # Lo [27] HANGUL SYLLABLE SYIG..HANGUL SYLLABLE SYIH +C2DC;H2 # Lo HANGUL SYLLABLE SI +C2DD..C2F7;H3 # Lo [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH +C2F8;H2 # Lo HANGUL SYLLABLE SSA +C2F9..C313;H3 # Lo [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH +C314;H2 # Lo HANGUL SYLLABLE SSAE +C315..C32F;H3 # Lo [27] HANGUL SYLLABLE SSAEG..HANGUL SYLLABLE SSAEH +C330;H2 # Lo HANGUL SYLLABLE SSYA +C331..C34B;H3 # Lo [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH +C34C;H2 # Lo HANGUL SYLLABLE SSYAE +C34D..C367;H3 # Lo [27] HANGUL SYLLABLE SSYAEG..HANGUL SYLLABLE SSYAEH +C368;H2 # Lo HANGUL SYLLABLE SSEO +C369..C383;H3 # Lo [27] HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH +C384;H2 # Lo HANGUL SYLLABLE SSE +C385..C39F;H3 # Lo [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH +C3A0;H2 # Lo HANGUL SYLLABLE SSYEO +C3A1..C3BB;H3 # Lo [27] HANGUL SYLLABLE SSYEOG..HANGUL SYLLABLE SSYEOH +C3BC;H2 # Lo HANGUL SYLLABLE SSYE +C3BD..C3D7;H3 # Lo [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH +C3D8;H2 # Lo HANGUL SYLLABLE SSO +C3D9..C3F3;H3 # Lo [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE SSOH +C3F4;H2 # Lo HANGUL SYLLABLE SSWA +C3F5..C40F;H3 # Lo [27] HANGUL SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH +C410;H2 # Lo HANGUL SYLLABLE SSWAE +C411..C42B;H3 # Lo [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH +C42C;H2 # Lo HANGUL SYLLABLE SSOE +C42D..C447;H3 # Lo [27] HANGUL SYLLABLE SSOEG..HANGUL SYLLABLE SSOEH +C448;H2 # Lo HANGUL SYLLABLE SSYO +C449..C463;H3 # Lo [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH +C464;H2 # Lo HANGUL SYLLABLE SSU +C465..C47F;H3 # Lo [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE SSUH +C480;H2 # Lo HANGUL SYLLABLE SSWEO +C481..C49B;H3 # Lo [27] HANGUL SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH +C49C;H2 # Lo HANGUL SYLLABLE SSWE +C49D..C4B7;H3 # Lo [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH +C4B8;H2 # Lo HANGUL SYLLABLE SSWI +C4B9..C4D3;H3 # Lo [27] HANGUL SYLLABLE SSWIG..HANGUL SYLLABLE SSWIH +C4D4;H2 # Lo HANGUL SYLLABLE SSYU +C4D5..C4EF;H3 # Lo [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH +C4F0;H2 # Lo HANGUL SYLLABLE SSEU +C4F1..C50B;H3 # Lo [27] HANGUL SYLLABLE SSEUG..HANGUL SYLLABLE SSEUH +C50C;H2 # Lo HANGUL SYLLABLE SSYI +C50D..C527;H3 # Lo [27] HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH +C528;H2 # Lo HANGUL SYLLABLE SSI +C529..C543;H3 # Lo [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH +C544;H2 # Lo HANGUL SYLLABLE A +C545..C55F;H3 # Lo [27] HANGUL SYLLABLE AG..HANGUL SYLLABLE AH +C560;H2 # Lo HANGUL SYLLABLE AE +C561..C57B;H3 # Lo [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH +C57C;H2 # Lo HANGUL SYLLABLE YA +C57D..C597;H3 # Lo [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH +C598;H2 # Lo HANGUL SYLLABLE YAE +C599..C5B3;H3 # Lo [27] HANGUL SYLLABLE YAEG..HANGUL SYLLABLE YAEH +C5B4;H2 # Lo HANGUL SYLLABLE EO +C5B5..C5CF;H3 # Lo [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH +C5D0;H2 # Lo HANGUL SYLLABLE E +C5D1..C5EB;H3 # Lo [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH +C5EC;H2 # Lo HANGUL SYLLABLE YEO +C5ED..C607;H3 # Lo [27] HANGUL SYLLABLE YEOG..HANGUL SYLLABLE YEOH +C608;H2 # Lo HANGUL SYLLABLE YE +C609..C623;H3 # Lo [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH +C624;H2 # Lo HANGUL SYLLABLE O +C625..C63F;H3 # Lo [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH +C640;H2 # Lo HANGUL SYLLABLE WA +C641..C65B;H3 # Lo [27] HANGUL SYLLABLE WAG..HANGUL SYLLABLE WAH +C65C;H2 # Lo HANGUL SYLLABLE WAE +C65D..C677;H3 # Lo [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH +C678;H2 # Lo HANGUL SYLLABLE OE +C679..C693;H3 # Lo [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH +C694;H2 # Lo HANGUL SYLLABLE YO +C695..C6AF;H3 # Lo [27] HANGUL SYLLABLE YOG..HANGUL SYLLABLE YOH +C6B0;H2 # Lo HANGUL SYLLABLE U +C6B1..C6CB;H3 # Lo [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH +C6CC;H2 # Lo HANGUL SYLLABLE WEO +C6CD..C6E7;H3 # Lo [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH +C6E8;H2 # Lo HANGUL SYLLABLE WE +C6E9..C703;H3 # Lo [27] HANGUL SYLLABLE WEG..HANGUL SYLLABLE WEH +C704;H2 # Lo HANGUL SYLLABLE WI +C705..C71F;H3 # Lo [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH +C720;H2 # Lo HANGUL SYLLABLE YU +C721..C73B;H3 # Lo [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH +C73C;H2 # Lo HANGUL SYLLABLE EU +C73D..C757;H3 # Lo [27] HANGUL SYLLABLE EUG..HANGUL SYLLABLE EUH +C758;H2 # Lo HANGUL SYLLABLE YI +C759..C773;H3 # Lo [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH +C774;H2 # Lo HANGUL SYLLABLE I +C775..C78F;H3 # Lo [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH +C790;H2 # Lo HANGUL SYLLABLE JA +C791..C7AB;H3 # Lo [27] HANGUL SYLLABLE JAG..HANGUL SYLLABLE JAH +C7AC;H2 # Lo HANGUL SYLLABLE JAE +C7AD..C7C7;H3 # Lo [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH +C7C8;H2 # Lo HANGUL SYLLABLE JYA +C7C9..C7E3;H3 # Lo [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH +C7E4;H2 # Lo HANGUL SYLLABLE JYAE +C7E5..C7FF;H3 # Lo [27] HANGUL SYLLABLE JYAEG..HANGUL SYLLABLE JYAEH +C800;H2 # Lo HANGUL SYLLABLE JEO +C801..C81B;H3 # Lo [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH +C81C;H2 # Lo HANGUL SYLLABLE JE +C81D..C837;H3 # Lo [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE JEH +C838;H2 # Lo HANGUL SYLLABLE JYEO +C839..C853;H3 # Lo [27] HANGUL SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH +C854;H2 # Lo HANGUL SYLLABLE JYE +C855..C86F;H3 # Lo [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH +C870;H2 # Lo HANGUL SYLLABLE JO +C871..C88B;H3 # Lo [27] HANGUL SYLLABLE JOG..HANGUL SYLLABLE JOH +C88C;H2 # Lo HANGUL SYLLABLE JWA +C88D..C8A7;H3 # Lo [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH +C8A8;H2 # Lo HANGUL SYLLABLE JWAE +C8A9..C8C3;H3 # Lo [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH +C8C4;H2 # Lo HANGUL SYLLABLE JOE +C8C5..C8DF;H3 # Lo [27] HANGUL SYLLABLE JOEG..HANGUL SYLLABLE JOEH +C8E0;H2 # Lo HANGUL SYLLABLE JYO +C8E1..C8FB;H3 # Lo [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH +C8FC;H2 # Lo HANGUL SYLLABLE JU +C8FD..C917;H3 # Lo [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH +C918;H2 # Lo HANGUL SYLLABLE JWEO +C919..C933;H3 # Lo [27] HANGUL SYLLABLE JWEOG..HANGUL SYLLABLE JWEOH +C934;H2 # Lo HANGUL SYLLABLE JWE +C935..C94F;H3 # Lo [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH +C950;H2 # Lo HANGUL SYLLABLE JWI +C951..C96B;H3 # Lo [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE JWIH +C96C;H2 # Lo HANGUL SYLLABLE JYU +C96D..C987;H3 # Lo [27] HANGUL SYLLABLE JYUG..HANGUL SYLLABLE JYUH +C988;H2 # Lo HANGUL SYLLABLE JEU +C989..C9A3;H3 # Lo [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH +C9A4;H2 # Lo HANGUL SYLLABLE JYI +C9A5..C9BF;H3 # Lo [27] HANGUL SYLLABLE JYIG..HANGUL SYLLABLE JYIH +C9C0;H2 # Lo HANGUL SYLLABLE JI +C9C1..C9DB;H3 # Lo [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH +C9DC;H2 # Lo HANGUL SYLLABLE JJA +C9DD..C9F7;H3 # Lo [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH +C9F8;H2 # Lo HANGUL SYLLABLE JJAE +C9F9..CA13;H3 # Lo [27] HANGUL SYLLABLE JJAEG..HANGUL SYLLABLE JJAEH +CA14;H2 # Lo HANGUL SYLLABLE JJYA +CA15..CA2F;H3 # Lo [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH +CA30;H2 # Lo HANGUL SYLLABLE JJYAE +CA31..CA4B;H3 # Lo [27] HANGUL SYLLABLE JJYAEG..HANGUL SYLLABLE JJYAEH +CA4C;H2 # Lo HANGUL SYLLABLE JJEO +CA4D..CA67;H3 # Lo [27] HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH +CA68;H2 # Lo HANGUL SYLLABLE JJE +CA69..CA83;H3 # Lo [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH +CA84;H2 # Lo HANGUL SYLLABLE JJYEO +CA85..CA9F;H3 # Lo [27] HANGUL SYLLABLE JJYEOG..HANGUL SYLLABLE JJYEOH +CAA0;H2 # Lo HANGUL SYLLABLE JJYE +CAA1..CABB;H3 # Lo [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH +CABC;H2 # Lo HANGUL SYLLABLE JJO +CABD..CAD7;H3 # Lo [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE JJOH +CAD8;H2 # Lo HANGUL SYLLABLE JJWA +CAD9..CAF3;H3 # Lo [27] HANGUL SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH +CAF4;H2 # Lo HANGUL SYLLABLE JJWAE +CAF5..CB0F;H3 # Lo [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH +CB10;H2 # Lo HANGUL SYLLABLE JJOE +CB11..CB2B;H3 # Lo [27] HANGUL SYLLABLE JJOEG..HANGUL SYLLABLE JJOEH +CB2C;H2 # Lo HANGUL SYLLABLE JJYO +CB2D..CB47;H3 # Lo [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH +CB48;H2 # Lo HANGUL SYLLABLE JJU +CB49..CB63;H3 # Lo [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE JJUH +CB64;H2 # Lo HANGUL SYLLABLE JJWEO +CB65..CB7F;H3 # Lo [27] HANGUL SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH +CB80;H2 # Lo HANGUL SYLLABLE JJWE +CB81..CB9B;H3 # Lo [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH +CB9C;H2 # Lo HANGUL SYLLABLE JJWI +CB9D..CBB7;H3 # Lo [27] HANGUL SYLLABLE JJWIG..HANGUL SYLLABLE JJWIH +CBB8;H2 # Lo HANGUL SYLLABLE JJYU +CBB9..CBD3;H3 # Lo [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH +CBD4;H2 # Lo HANGUL SYLLABLE JJEU +CBD5..CBEF;H3 # Lo [27] HANGUL SYLLABLE JJEUG..HANGUL SYLLABLE JJEUH +CBF0;H2 # Lo HANGUL SYLLABLE JJYI +CBF1..CC0B;H3 # Lo [27] HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH +CC0C;H2 # Lo HANGUL SYLLABLE JJI +CC0D..CC27;H3 # Lo [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH +CC28;H2 # Lo HANGUL SYLLABLE CA +CC29..CC43;H3 # Lo [27] HANGUL SYLLABLE CAG..HANGUL SYLLABLE CAH +CC44;H2 # Lo HANGUL SYLLABLE CAE +CC45..CC5F;H3 # Lo [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH +CC60;H2 # Lo HANGUL SYLLABLE CYA +CC61..CC7B;H3 # Lo [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH +CC7C;H2 # Lo HANGUL SYLLABLE CYAE +CC7D..CC97;H3 # Lo [27] HANGUL SYLLABLE CYAEG..HANGUL SYLLABLE CYAEH +CC98;H2 # Lo HANGUL SYLLABLE CEO +CC99..CCB3;H3 # Lo [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH +CCB4;H2 # Lo HANGUL SYLLABLE CE +CCB5..CCCF;H3 # Lo [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE CEH +CCD0;H2 # Lo HANGUL SYLLABLE CYEO +CCD1..CCEB;H3 # Lo [27] HANGUL SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH +CCEC;H2 # Lo HANGUL SYLLABLE CYE +CCED..CD07;H3 # Lo [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH +CD08;H2 # Lo HANGUL SYLLABLE CO +CD09..CD23;H3 # Lo [27] HANGUL SYLLABLE COG..HANGUL SYLLABLE COH +CD24;H2 # Lo HANGUL SYLLABLE CWA +CD25..CD3F;H3 # Lo [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH +CD40;H2 # Lo HANGUL SYLLABLE CWAE +CD41..CD5B;H3 # Lo [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH +CD5C;H2 # Lo HANGUL SYLLABLE COE +CD5D..CD77;H3 # Lo [27] HANGUL SYLLABLE COEG..HANGUL SYLLABLE COEH +CD78;H2 # Lo HANGUL SYLLABLE CYO +CD79..CD93;H3 # Lo [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH +CD94;H2 # Lo HANGUL SYLLABLE CU +CD95..CDAF;H3 # Lo [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH +CDB0;H2 # Lo HANGUL SYLLABLE CWEO +CDB1..CDCB;H3 # Lo [27] HANGUL SYLLABLE CWEOG..HANGUL SYLLABLE CWEOH +CDCC;H2 # Lo HANGUL SYLLABLE CWE +CDCD..CDE7;H3 # Lo [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH +CDE8;H2 # Lo HANGUL SYLLABLE CWI +CDE9..CE03;H3 # Lo [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE CWIH +CE04;H2 # Lo HANGUL SYLLABLE CYU +CE05..CE1F;H3 # Lo [27] HANGUL SYLLABLE CYUG..HANGUL SYLLABLE CYUH +CE20;H2 # Lo HANGUL SYLLABLE CEU +CE21..CE3B;H3 # Lo [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH +CE3C;H2 # Lo HANGUL SYLLABLE CYI +CE3D..CE57;H3 # Lo [27] HANGUL SYLLABLE CYIG..HANGUL SYLLABLE CYIH +CE58;H2 # Lo HANGUL SYLLABLE CI +CE59..CE73;H3 # Lo [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH +CE74;H2 # Lo HANGUL SYLLABLE KA +CE75..CE8F;H3 # Lo [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH +CE90;H2 # Lo HANGUL SYLLABLE KAE +CE91..CEAB;H3 # Lo [27] HANGUL SYLLABLE KAEG..HANGUL SYLLABLE KAEH +CEAC;H2 # Lo HANGUL SYLLABLE KYA +CEAD..CEC7;H3 # Lo [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH +CEC8;H2 # Lo HANGUL SYLLABLE KYAE +CEC9..CEE3;H3 # Lo [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE KYAEH +CEE4;H2 # Lo HANGUL SYLLABLE KEO +CEE5..CEFF;H3 # Lo [27] HANGUL SYLLABLE KEOG..HANGUL SYLLABLE KEOH +CF00;H2 # Lo HANGUL SYLLABLE KE +CF01..CF1B;H3 # Lo [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH +CF1C;H2 # Lo HANGUL SYLLABLE KYEO +CF1D..CF37;H3 # Lo [27] HANGUL SYLLABLE KYEOG..HANGUL SYLLABLE KYEOH +CF38;H2 # Lo HANGUL SYLLABLE KYE +CF39..CF53;H3 # Lo [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH +CF54;H2 # Lo HANGUL SYLLABLE KO +CF55..CF6F;H3 # Lo [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE KOH +CF70;H2 # Lo HANGUL SYLLABLE KWA +CF71..CF8B;H3 # Lo [27] HANGUL SYLLABLE KWAG..HANGUL SYLLABLE KWAH +CF8C;H2 # Lo HANGUL SYLLABLE KWAE +CF8D..CFA7;H3 # Lo [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH +CFA8;H2 # Lo HANGUL SYLLABLE KOE +CFA9..CFC3;H3 # Lo [27] HANGUL SYLLABLE KOEG..HANGUL SYLLABLE KOEH +CFC4;H2 # Lo HANGUL SYLLABLE KYO +CFC5..CFDF;H3 # Lo [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH +CFE0;H2 # Lo HANGUL SYLLABLE KU +CFE1..CFFB;H3 # Lo [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH +CFFC;H2 # Lo HANGUL SYLLABLE KWEO +CFFD..D017;H3 # Lo [27] HANGUL SYLLABLE KWEOG..HANGUL SYLLABLE KWEOH +D018;H2 # Lo HANGUL SYLLABLE KWE +D019..D033;H3 # Lo [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH +D034;H2 # Lo HANGUL SYLLABLE KWI +D035..D04F;H3 # Lo [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE KWIH +D050;H2 # Lo HANGUL SYLLABLE KYU +D051..D06B;H3 # Lo [27] HANGUL SYLLABLE KYUG..HANGUL SYLLABLE KYUH +D06C;H2 # Lo HANGUL SYLLABLE KEU +D06D..D087;H3 # Lo [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH +D088;H2 # Lo HANGUL SYLLABLE KYI +D089..D0A3;H3 # Lo [27] HANGUL SYLLABLE KYIG..HANGUL SYLLABLE KYIH +D0A4;H2 # Lo HANGUL SYLLABLE KI +D0A5..D0BF;H3 # Lo [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH +D0C0;H2 # Lo HANGUL SYLLABLE TA +D0C1..D0DB;H3 # Lo [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH +D0DC;H2 # Lo HANGUL SYLLABLE TAE +D0DD..D0F7;H3 # Lo [27] HANGUL SYLLABLE TAEG..HANGUL SYLLABLE TAEH +D0F8;H2 # Lo HANGUL SYLLABLE TYA +D0F9..D113;H3 # Lo [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH +D114;H2 # Lo HANGUL SYLLABLE TYAE +D115..D12F;H3 # Lo [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE TYAEH +D130;H2 # Lo HANGUL SYLLABLE TEO +D131..D14B;H3 # Lo [27] HANGUL SYLLABLE TEOG..HANGUL SYLLABLE TEOH +D14C;H2 # Lo HANGUL SYLLABLE TE +D14D..D167;H3 # Lo [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH +D168;H2 # Lo HANGUL SYLLABLE TYEO +D169..D183;H3 # Lo [27] HANGUL SYLLABLE TYEOG..HANGUL SYLLABLE TYEOH +D184;H2 # Lo HANGUL SYLLABLE TYE +D185..D19F;H3 # Lo [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH +D1A0;H2 # Lo HANGUL SYLLABLE TO +D1A1..D1BB;H3 # Lo [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE TOH +D1BC;H2 # Lo HANGUL SYLLABLE TWA +D1BD..D1D7;H3 # Lo [27] HANGUL SYLLABLE TWAG..HANGUL SYLLABLE TWAH +D1D8;H2 # Lo HANGUL SYLLABLE TWAE +D1D9..D1F3;H3 # Lo [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH +D1F4;H2 # Lo HANGUL SYLLABLE TOE +D1F5..D20F;H3 # Lo [27] HANGUL SYLLABLE TOEG..HANGUL SYLLABLE TOEH +D210;H2 # Lo HANGUL SYLLABLE TYO +D211..D22B;H3 # Lo [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH +D22C;H2 # Lo HANGUL SYLLABLE TU +D22D..D247;H3 # Lo [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH +D248;H2 # Lo HANGUL SYLLABLE TWEO +D249..D263;H3 # Lo [27] HANGUL SYLLABLE TWEOG..HANGUL SYLLABLE TWEOH +D264;H2 # Lo HANGUL SYLLABLE TWE +D265..D27F;H3 # Lo [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH +D280;H2 # Lo HANGUL SYLLABLE TWI +D281..D29B;H3 # Lo [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE TWIH +D29C;H2 # Lo HANGUL SYLLABLE TYU +D29D..D2B7;H3 # Lo [27] HANGUL SYLLABLE TYUG..HANGUL SYLLABLE TYUH +D2B8;H2 # Lo HANGUL SYLLABLE TEU +D2B9..D2D3;H3 # Lo [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH +D2D4;H2 # Lo HANGUL SYLLABLE TYI +D2D5..D2EF;H3 # Lo [27] HANGUL SYLLABLE TYIG..HANGUL SYLLABLE TYIH +D2F0;H2 # Lo HANGUL SYLLABLE TI +D2F1..D30B;H3 # Lo [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH +D30C;H2 # Lo HANGUL SYLLABLE PA +D30D..D327;H3 # Lo [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH +D328;H2 # Lo HANGUL SYLLABLE PAE +D329..D343;H3 # Lo [27] HANGUL SYLLABLE PAEG..HANGUL SYLLABLE PAEH +D344;H2 # Lo HANGUL SYLLABLE PYA +D345..D35F;H3 # Lo [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH +D360;H2 # Lo HANGUL SYLLABLE PYAE +D361..D37B;H3 # Lo [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE PYAEH +D37C;H2 # Lo HANGUL SYLLABLE PEO +D37D..D397;H3 # Lo [27] HANGUL SYLLABLE PEOG..HANGUL SYLLABLE PEOH +D398;H2 # Lo HANGUL SYLLABLE PE +D399..D3B3;H3 # Lo [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH +D3B4;H2 # Lo HANGUL SYLLABLE PYEO +D3B5..D3CF;H3 # Lo [27] HANGUL SYLLABLE PYEOG..HANGUL SYLLABLE PYEOH +D3D0;H2 # Lo HANGUL SYLLABLE PYE +D3D1..D3EB;H3 # Lo [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH +D3EC;H2 # Lo HANGUL SYLLABLE PO +D3ED..D407;H3 # Lo [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE POH +D408;H2 # Lo HANGUL SYLLABLE PWA +D409..D423;H3 # Lo [27] HANGUL SYLLABLE PWAG..HANGUL SYLLABLE PWAH +D424;H2 # Lo HANGUL SYLLABLE PWAE +D425..D43F;H3 # Lo [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH +D440;H2 # Lo HANGUL SYLLABLE POE +D441..D45B;H3 # Lo [27] HANGUL SYLLABLE POEG..HANGUL SYLLABLE POEH +D45C;H2 # Lo HANGUL SYLLABLE PYO +D45D..D477;H3 # Lo [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH +D478;H2 # Lo HANGUL SYLLABLE PU +D479..D493;H3 # Lo [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH +D494;H2 # Lo HANGUL SYLLABLE PWEO +D495..D4AF;H3 # Lo [27] HANGUL SYLLABLE PWEOG..HANGUL SYLLABLE PWEOH +D4B0;H2 # Lo HANGUL SYLLABLE PWE +D4B1..D4CB;H3 # Lo [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH +D4CC;H2 # Lo HANGUL SYLLABLE PWI +D4CD..D4E7;H3 # Lo [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE PWIH +D4E8;H2 # Lo HANGUL SYLLABLE PYU +D4E9..D503;H3 # Lo [27] HANGUL SYLLABLE PYUG..HANGUL SYLLABLE PYUH +D504;H2 # Lo HANGUL SYLLABLE PEU +D505..D51F;H3 # Lo [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH +D520;H2 # Lo HANGUL SYLLABLE PYI +D521..D53B;H3 # Lo [27] HANGUL SYLLABLE PYIG..HANGUL SYLLABLE PYIH +D53C;H2 # Lo HANGUL SYLLABLE PI +D53D..D557;H3 # Lo [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH +D558;H2 # Lo HANGUL SYLLABLE HA +D559..D573;H3 # Lo [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH +D574;H2 # Lo HANGUL SYLLABLE HAE +D575..D58F;H3 # Lo [27] HANGUL SYLLABLE HAEG..HANGUL SYLLABLE HAEH +D590;H2 # Lo HANGUL SYLLABLE HYA +D591..D5AB;H3 # Lo [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH +D5AC;H2 # Lo HANGUL SYLLABLE HYAE +D5AD..D5C7;H3 # Lo [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE HYAEH +D5C8;H2 # Lo HANGUL SYLLABLE HEO +D5C9..D5E3;H3 # Lo [27] HANGUL SYLLABLE HEOG..HANGUL SYLLABLE HEOH +D5E4;H2 # Lo HANGUL SYLLABLE HE +D5E5..D5FF;H3 # Lo [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH +D600;H2 # Lo HANGUL SYLLABLE HYEO +D601..D61B;H3 # Lo [27] HANGUL SYLLABLE HYEOG..HANGUL SYLLABLE HYEOH +D61C;H2 # Lo HANGUL SYLLABLE HYE +D61D..D637;H3 # Lo [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH +D638;H2 # Lo HANGUL SYLLABLE HO +D639..D653;H3 # Lo [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE HOH +D654;H2 # Lo HANGUL SYLLABLE HWA +D655..D66F;H3 # Lo [27] HANGUL SYLLABLE HWAG..HANGUL SYLLABLE HWAH +D670;H2 # Lo HANGUL SYLLABLE HWAE +D671..D68B;H3 # Lo [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH +D68C;H2 # Lo HANGUL SYLLABLE HOE +D68D..D6A7;H3 # Lo [27] HANGUL SYLLABLE HOEG..HANGUL SYLLABLE HOEH +D6A8;H2 # Lo HANGUL SYLLABLE HYO +D6A9..D6C3;H3 # Lo [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH +D6C4;H2 # Lo HANGUL SYLLABLE HU +D6C5..D6DF;H3 # Lo [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH +D6E0;H2 # Lo HANGUL SYLLABLE HWEO +D6E1..D6FB;H3 # Lo [27] HANGUL SYLLABLE HWEOG..HANGUL SYLLABLE HWEOH +D6FC;H2 # Lo HANGUL SYLLABLE HWE +D6FD..D717;H3 # Lo [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH +D718;H2 # Lo HANGUL SYLLABLE HWI +D719..D733;H3 # Lo [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE HWIH +D734;H2 # Lo HANGUL SYLLABLE HYU +D735..D74F;H3 # Lo [27] HANGUL SYLLABLE HYUG..HANGUL SYLLABLE HYUH +D750;H2 # Lo HANGUL SYLLABLE HEU +D751..D76B;H3 # Lo [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH +D76C;H2 # Lo HANGUL SYLLABLE HYI +D76D..D787;H3 # Lo [27] HANGUL SYLLABLE HYIG..HANGUL SYLLABLE HYIH +D788;H2 # Lo HANGUL SYLLABLE HI +D789..D7A3;H3 # Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH +D7B0..D7C6;JV # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E +D7CB..D7FB;JT # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH +D800..DB7F;SG # Cs [896] .. +DB80..DBFF;SG # Cs [128] .. +DC00..DFFF;SG # Cs [1024] .. +E000..F8FF;XX # Co [6400] .. +F900..FA6D;ID # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D +FA6E..FA6F;ID # Cn [2] .. +FA70..FAD9;ID # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 +FADA..FAFF;ID # Cn [38] .. +FB00..FB06;AL # Ll [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST +FB13..FB17;AL # Ll [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH +FB1D;HL # Lo HEBREW LETTER YOD WITH HIRIQ +FB1E;CM # Mn HEBREW POINT JUDEO-SPANISH VARIKA +FB1F..FB28;HL # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV +FB29;AL # Sm HEBREW LETTER ALTERNATIVE PLUS SIGN +FB2A..FB36;HL # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH +FB38..FB3C;HL # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH +FB3E;HL # Lo HEBREW LETTER MEM WITH DAGESH +FB40..FB41;HL # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH +FB43..FB44;HL # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH +FB46..FB4F;HL # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED +FB50..FBB1;AL # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM +FBB2..FBC1;AL # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW +FBD3..FD3D;AL # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM +FD3E;CL # Pe ORNATE LEFT PARENTHESIS +FD3F;OP # Ps ORNATE RIGHT PARENTHESIS +FD50..FD8F;AL # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FD92..FDC7;AL # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM +FDF0..FDFB;AL # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU +FDFC;PO # Sc RIAL SIGN +FDFD;AL # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM +FE00..FE0F;CM # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 +FE10;IS # Po PRESENTATION FORM FOR VERTICAL COMMA +FE11..FE12;CL # Po [2] PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA..PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP +FE13..FE14;IS # Po [2] PRESENTATION FORM FOR VERTICAL COLON..PRESENTATION FORM FOR VERTICAL SEMICOLON +FE15..FE16;EX # Po [2] PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK..PRESENTATION FORM FOR VERTICAL QUESTION MARK +FE17;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET +FE18;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET +FE19;IN # Po PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS +FE20..FE2F;CM # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF +FE30;ID # Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER +FE31..FE32;ID # Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH +FE33..FE34;ID # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE +FE35;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS +FE36;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS +FE37;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET +FE38;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET +FE39;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET +FE3A;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET +FE3B;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET +FE3C;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET +FE3D;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET +FE3E;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET +FE3F;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET +FE40;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET +FE41;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET +FE42;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET +FE43;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET +FE44;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET +FE45..FE46;ID # Po [2] SESAME DOT..WHITE SESAME DOT +FE47;OP # Ps PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET +FE48;CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET +FE49..FE4C;ID # Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE +FE4D..FE4F;ID # Pc [3] DASHED LOW LINE..WAVY LOW LINE +FE50;CL # Po SMALL COMMA +FE51;ID # Po SMALL IDEOGRAPHIC COMMA +FE52;CL # Po SMALL FULL STOP +FE54..FE55;NS # Po [2] SMALL SEMICOLON..SMALL COLON +FE56..FE57;EX # Po [2] SMALL QUESTION MARK..SMALL EXCLAMATION MARK +FE58;ID # Pd SMALL EM DASH +FE59;OP # Ps SMALL LEFT PARENTHESIS +FE5A;CL # Pe SMALL RIGHT PARENTHESIS +FE5B;OP # Ps SMALL LEFT CURLY BRACKET +FE5C;CL # Pe SMALL RIGHT CURLY BRACKET +FE5D;OP # Ps SMALL LEFT TORTOISE SHELL BRACKET +FE5E;CL # Pe SMALL RIGHT TORTOISE SHELL BRACKET +FE5F..FE61;ID # Po [3] SMALL NUMBER SIGN..SMALL ASTERISK +FE62;ID # Sm SMALL PLUS SIGN +FE63;ID # Pd SMALL HYPHEN-MINUS +FE64..FE66;ID # Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN +FE68;ID # Po SMALL REVERSE SOLIDUS +FE69;PR # Sc SMALL DOLLAR SIGN +FE6A;PO # Po SMALL PERCENT SIGN +FE6B;ID # Po SMALL COMMERCIAL AT +FE70..FE74;AL # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM +FE76..FEFC;AL # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM +FEFF;WJ # Cf ZERO WIDTH NO-BREAK SPACE +FF01;EX # Po FULLWIDTH EXCLAMATION MARK +FF02..FF03;ID # Po [2] FULLWIDTH QUOTATION MARK..FULLWIDTH NUMBER SIGN +FF04;PR # Sc FULLWIDTH DOLLAR SIGN +FF05;PO # Po FULLWIDTH PERCENT SIGN +FF06..FF07;ID # Po [2] FULLWIDTH AMPERSAND..FULLWIDTH APOSTROPHE +FF08;OP # Ps FULLWIDTH LEFT PARENTHESIS +FF09;CL # Pe FULLWIDTH RIGHT PARENTHESIS +FF0A;ID # Po FULLWIDTH ASTERISK +FF0B;ID # Sm FULLWIDTH PLUS SIGN +FF0C;CL # Po FULLWIDTH COMMA +FF0D;ID # Pd FULLWIDTH HYPHEN-MINUS +FF0E;CL # Po FULLWIDTH FULL STOP +FF0F;ID # Po FULLWIDTH SOLIDUS +FF10..FF19;ID # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE +FF1A..FF1B;NS # Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON +FF1C..FF1E;ID # Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN +FF1F;EX # Po FULLWIDTH QUESTION MARK +FF20;ID # Po FULLWIDTH COMMERCIAL AT +FF21..FF3A;ID # Lu [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z +FF3B;OP # Ps FULLWIDTH LEFT SQUARE BRACKET +FF3C;ID # Po FULLWIDTH REVERSE SOLIDUS +FF3D;CL # Pe FULLWIDTH RIGHT SQUARE BRACKET +FF3E;ID # Sk FULLWIDTH CIRCUMFLEX ACCENT +FF3F;ID # Pc FULLWIDTH LOW LINE +FF40;ID # Sk FULLWIDTH GRAVE ACCENT +FF41..FF5A;ID # Ll [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z +FF5B;OP # Ps FULLWIDTH LEFT CURLY BRACKET +FF5C;ID # Sm FULLWIDTH VERTICAL LINE +FF5D;CL # Pe FULLWIDTH RIGHT CURLY BRACKET +FF5E;ID # Sm FULLWIDTH TILDE +FF5F;OP # Ps FULLWIDTH LEFT WHITE PARENTHESIS +FF60;CL # Pe FULLWIDTH RIGHT WHITE PARENTHESIS +FF61;CL # Po HALFWIDTH IDEOGRAPHIC FULL STOP +FF62;OP # Ps HALFWIDTH LEFT CORNER BRACKET +FF63;CL # Pe HALFWIDTH RIGHT CORNER BRACKET +FF64;CL # Po HALFWIDTH IDEOGRAPHIC COMMA +FF65;NS # Po HALFWIDTH KATAKANA MIDDLE DOT +FF66;ID # Lo HALFWIDTH KATAKANA LETTER WO +FF67..FF6F;CJ # Lo [9] HALFWIDTH KATAKANA LETTER SMALL A..HALFWIDTH KATAKANA LETTER SMALL TU +FF70;CJ # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF71..FF9D;ID # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N +FF9E..FF9F;NS # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +FFA0..FFBE;ID # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH +FFC2..FFC7;ID # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E +FFCA..FFCF;ID # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE +FFD2..FFD7;ID # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU +FFDA..FFDC;ID # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I +FFE0;PO # Sc FULLWIDTH CENT SIGN +FFE1;PR # Sc FULLWIDTH POUND SIGN +FFE2;ID # Sm FULLWIDTH NOT SIGN +FFE3;ID # Sk FULLWIDTH MACRON +FFE4;ID # So FULLWIDTH BROKEN BAR +FFE5..FFE6;PR # Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN +FFE8;AL # So HALFWIDTH FORMS LIGHT VERTICAL +FFE9..FFEC;AL # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW +FFED..FFEE;AL # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE +FFF9..FFFB;CM # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR +FFFC;CB # So OBJECT REPLACEMENT CHARACTER +FFFD;AI # So REPLACEMENT CHARACTER +10000..1000B;AL # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE +1000D..10026;AL # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO +10028..1003A;AL # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO +1003C..1003D;AL # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE +1003F..1004D;AL # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO +10050..1005D;AL # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089 +10080..100FA;AL # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305 +10100..10102;BA # Po [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK +10107..10133;AL # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND +10137..1013F;AL # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT +10140..10174;AL # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS +10175..10178;AL # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN +10179..10189;AL # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN +1018A..1018B;AL # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN +1018C..1018E;AL # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN +10190..1019C;AL # So [13] ROMAN SEXTANS SIGN..ASCIA SYMBOL +101A0;AL # So GREEK SYMBOL TAU RHO +101D0..101FC;AL # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND +101FD;CM # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE +10280..1029C;AL # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X +102A0..102D0;AL # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3 +102E0;CM # Mn COPTIC EPACT THOUSANDS MARK +102E1..102FB;AL # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED +10300..1031F;AL # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS +10320..10323;AL # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY +1032D..1032F;AL # Lo [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE +10330..10340;AL # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA +10341;AL # Nl GOTHIC LETTER NINETY +10342..10349;AL # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL +1034A;AL # Nl GOTHIC LETTER NINE HUNDRED +10350..10375;AL # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA +10376..1037A;CM # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII +10380..1039D;AL # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU +1039F;BA # Po UGARITIC WORD DIVIDER +103A0..103C3;AL # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA +103C8..103CF;AL # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH +103D0;BA # Po OLD PERSIAN WORD DIVIDER +103D1..103D5;AL # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED +10400..1044F;AL # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW +10450..1047F;AL # Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW +10480..1049D;AL # Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO +104A0..104A9;NU # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE +104B0..104D3;AL # Lu [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB;AL # Ll [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA +10500..10527;AL # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE +10530..10563;AL # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW +1056F;AL # Po CAUCASIAN ALBANIAN CITATION MARK +10600..10736;AL # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 +10740..10755;AL # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE +10760..10767;AL # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 +10800..10805;AL # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA +10808;AL # Lo CYPRIOT SYLLABLE JO +1080A..10835;AL # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO +10837..10838;AL # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE +1083C;AL # Lo CYPRIOT SYLLABLE ZA +1083F;AL # Lo CYPRIOT SYLLABLE ZO +10840..10855;AL # Lo [22] IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW +10857;BA # Po IMPERIAL ARAMAIC SECTION SIGN +10858..1085F;AL # No [8] IMPERIAL ARAMAIC NUMBER ONE..IMPERIAL ARAMAIC NUMBER TEN THOUSAND +10860..10876;AL # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW +10877..10878;AL # So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON +10879..1087F;AL # No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY +10880..1089E;AL # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW +108A7..108AF;AL # No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED +108E0..108F2;AL # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH +108F4..108F5;AL # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW +108FB..108FF;AL # No [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED +10900..10915;AL # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU +10916..1091B;AL # No [6] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER THREE +1091F;BA # Po PHOENICIAN WORD SEPARATOR +10920..10939;AL # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C +1093F;AL # Po LYDIAN TRIANGULAR MARK +10980..1099F;AL # Lo [32] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2 +109A0..109B7;AL # Lo [24] MEROITIC CURSIVE LETTER A..MEROITIC CURSIVE LETTER DA +109BC..109BD;AL # No [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF +109BE..109BF;AL # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN +109C0..109CF;AL # No [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY +109D2..109FF;AL # No [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS +10A00;AL # Lo KHAROSHTHI LETTER A +10A01..10A03;CM # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R +10A05..10A06;CM # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O +10A0C..10A0F;CM # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA +10A10..10A13;AL # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA +10A15..10A17;AL # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA +10A19..10A35;AL # Lo [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA +10A38..10A3A;CM # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW +10A3F;CM # Mn KHAROSHTHI VIRAMA +10A40..10A48;AL # No [9] KHAROSHTHI DIGIT ONE..KHAROSHTHI FRACTION ONE HALF +10A50..10A57;BA # Po [8] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION DOUBLE DANDA +10A58;AL # Po KHAROSHTHI PUNCTUATION LINES +10A60..10A7C;AL # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH +10A7D..10A7E;AL # No [2] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMBER FIFTY +10A7F;AL # Po OLD SOUTH ARABIAN NUMERIC INDICATOR +10A80..10A9C;AL # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH +10A9D..10A9F;AL # No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY +10AC0..10AC7;AL # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW +10AC8;AL # So MANICHAEAN SIGN UD +10AC9..10AE4;AL # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW +10AE5..10AE6;CM # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW +10AEB..10AEF;AL # No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED +10AF0..10AF5;BA # Po [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS +10AF6;IN # Po MANICHAEAN PUNCTUATION LINE FILLER +10B00..10B35;AL # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE +10B39..10B3F;BA # Po [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION +10B40..10B55;AL # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW +10B58..10B5F;AL # No [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND +10B60..10B72;AL # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW +10B78..10B7F;AL # No [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND +10B80..10B91;AL # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW +10B99..10B9C;AL # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT +10BA9..10BAF;AL # No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED +10C00..10C48;AL # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH +10C80..10CB2;AL # Lu [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10CC0..10CF2;AL # Ll [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10CFA..10CFF;AL # No [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND +10D00..10D23;AL # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10D24..10D27;CM # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D30..10D39;NU # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10E60..10E7E;AL # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS +10E80..10EA9;AL # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET +10EAB..10EAC;CM # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK +10EAD;BA # Pd YEZIDI HYPHENATION MARK +10EB0..10EB1;AL # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10F00..10F1C;AL # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL +10F1D..10F26;AL # No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF +10F27;AL # Lo OLD SOGDIAN LIGATURE AYIN-DALETH +10F30..10F45;AL # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN +10F46..10F50;CM # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW +10F51..10F54;AL # No [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED +10F55..10F59;AL # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT +10FB0..10FC4;AL # Lo [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW +10FC5..10FCB;AL # No [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED +10FE0..10FF6;AL # Lo [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH +11000;CM # Mc BRAHMI SIGN CANDRABINDU +11001;CM # Mn BRAHMI SIGN ANUSVARA +11002;CM # Mc BRAHMI SIGN VISARGA +11003..11037;AL # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA +11038..11046;CM # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA +11047..11048;BA # Po [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA +11049..1104D;AL # Po [5] BRAHMI PUNCTUATION DOT..BRAHMI PUNCTUATION LOTUS +11052..11065;AL # No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND +11066..1106F;NU # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE +1107F;CM # Mn BRAHMI NUMBER JOINER +11080..11081;CM # Mn [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA +11082;CM # Mc KAITHI SIGN VISARGA +11083..110AF;AL # Lo [45] KAITHI LETTER A..KAITHI LETTER HA +110B0..110B2;CM # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II +110B3..110B6;CM # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI +110B7..110B8;CM # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU +110B9..110BA;CM # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA +110BB..110BC;AL # Po [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN +110BD;AL # Cf KAITHI NUMBER SIGN +110BE..110C1;BA # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA +110CD;AL # Cf KAITHI NUMBER SIGN ABOVE +110D0..110E8;AL # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE +110F0..110F9;NU # Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE +11100..11102;CM # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA +11103..11126;AL # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA +11127..1112B;CM # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU +1112C;CM # Mc CHAKMA VOWEL SIGN E +1112D..11134;CM # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA +11136..1113F;NU # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE +11140..11143;BA # Po [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK +11144;AL # Lo CHAKMA LETTER LHAA +11145..11146;CM # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI +11147;AL # Lo CHAKMA LETTER VAA +11150..11172;AL # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA +11173;CM # Mn MAHAJANI SIGN NUKTA +11174;AL # Po MAHAJANI ABBREVIATION SIGN +11175;BB # Po MAHAJANI SECTION MARK +11176;AL # Lo MAHAJANI LIGATURE SHRI +11180..11181;CM # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA +11182;CM # Mc SHARADA SIGN VISARGA +11183..111B2;AL # Lo [48] SHARADA LETTER A..SHARADA LETTER HA +111B3..111B5;CM # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II +111B6..111BE;CM # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O +111BF..111C0;CM # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA +111C1..111C4;AL # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM +111C5..111C6;BA # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA +111C7;AL # Po SHARADA ABBREVIATION SIGN +111C8;BA # Po SHARADA SEPARATOR +111C9..111CC;CM # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK +111CD;AL # Po SHARADA SUTRA MARK +111CE;CM # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E +111CF;CM # Mn SHARADA SIGN INVERTED CANDRABINDU +111D0..111D9;NU # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE +111DA;AL # Lo SHARADA EKAM +111DB;BB # Po SHARADA SIGN SIDDHAM +111DC;AL # Lo SHARADA HEADSTROKE +111DD..111DF;BA # Po [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2 +111E1..111F4;AL # No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND +11200..11211;AL # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA +11213..1122B;AL # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA +1122C..1122E;CM # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II +1122F..11231;CM # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +11232..11233;CM # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU +11234;CM # Mn KHOJKI SIGN ANUSVARA +11235;CM # Mc KHOJKI SIGN VIRAMA +11236..11237;CM # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +11238..11239;BA # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA +1123A;AL # Po KHOJKI WORD SEPARATOR +1123B..1123C;BA # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK +1123D;AL # Po KHOJKI ABBREVIATION SIGN +1123E;CM # Mn KHOJKI SIGN SUKUN +11280..11286;AL # Lo [7] MULTANI LETTER A..MULTANI LETTER GA +11288;AL # Lo MULTANI LETTER GHA +1128A..1128D;AL # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA +1128F..1129D;AL # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA +1129F..112A8;AL # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA +112A9;BA # Po MULTANI SECTION MARK +112B0..112DE;AL # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA +112DF;CM # Mn KHUDAWADI SIGN ANUSVARA +112E0..112E2;CM # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II +112E3..112EA;CM # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA +112F0..112F9;NU # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE +11300..11301;CM # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU +11302..11303;CM # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +11305..1130C;AL # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L +1130F..11310;AL # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI +11313..11328;AL # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA +1132A..11330;AL # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA +11332..11333;AL # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA +11335..11339;AL # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA +1133B..1133C;CM # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA +1133D;AL # Lo GRANTHA SIGN AVAGRAHA +1133E..1133F;CM # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I +11340;CM # Mn GRANTHA VOWEL SIGN II +11341..11344;CM # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR +11347..11348;CM # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +1134B..1134D;CM # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +11350;AL # Lo GRANTHA OM +11357;CM # Mc GRANTHA AU LENGTH MARK +1135D..11361;AL # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11362..11363;CM # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11366..1136C;CM # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +11370..11374;CM # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11400..11434;AL # Lo [53] NEWA LETTER A..NEWA LETTER HA +11435..11437;CM # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F;CM # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441;CM # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444;CM # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445;CM # Mc NEWA SIGN VISARGA +11446;CM # Mn NEWA SIGN NUKTA +11447..1144A;AL # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI +1144B..1144E;BA # Po [4] NEWA DANDA..NEWA GAP FILLER +1144F;AL # Po NEWA ABBREVIATION SIGN +11450..11459;NU # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE +1145A..1145B;BA # Po [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK +1145D;AL # Po NEWA INSERTION SIGN +1145E;CM # Mn NEWA SANDHI MARK +1145F..11461;AL # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA +11480..114AF;AL # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA +114B0..114B2;CM # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II +114B3..114B8;CM # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL +114B9;CM # Mc TIRHUTA VOWEL SIGN E +114BA;CM # Mn TIRHUTA VOWEL SIGN SHORT E +114BB..114BE;CM # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU +114BF..114C0;CM # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA +114C1;CM # Mc TIRHUTA SIGN VISARGA +114C2..114C3;CM # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +114C4..114C5;AL # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG +114C6;AL # Po TIRHUTA ABBREVIATION SIGN +114C7;AL # Lo TIRHUTA OM +114D0..114D9;NU # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE +11580..115AE;AL # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA +115AF..115B1;CM # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II +115B2..115B5;CM # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR +115B8..115BB;CM # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +115BC..115BD;CM # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +115BE;CM # Mc SIDDHAM SIGN VISARGA +115BF..115C0;CM # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA +115C1;BB # Po SIDDHAM SIGN SIDDHAM +115C2..115C3;BA # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA +115C4..115C5;EX # Po [2] SIDDHAM SEPARATOR DOT..SIDDHAM SEPARATOR BAR +115C6..115C8;AL # Po [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3 +115C9..115D7;BA # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES +115D8..115DB;AL # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U +115DC..115DD;CM # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU +11600..1162F;AL # Lo [48] MODI LETTER A..MODI LETTER LLA +11630..11632;CM # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II +11633..1163A;CM # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI +1163B..1163C;CM # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU +1163D;CM # Mn MODI SIGN ANUSVARA +1163E;CM # Mc MODI SIGN VISARGA +1163F..11640;CM # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA +11641..11642;BA # Po [2] MODI DANDA..MODI DOUBLE DANDA +11643;AL # Po MODI ABBREVIATION SIGN +11644;AL # Lo MODI SIGN HUVA +11650..11659;NU # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE +11660..1166C;BB # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT +11680..116AA;AL # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA +116AB;CM # Mn TAKRI SIGN ANUSVARA +116AC;CM # Mc TAKRI SIGN VISARGA +116AD;CM # Mn TAKRI VOWEL SIGN AA +116AE..116AF;CM # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II +116B0..116B5;CM # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +116B6;CM # Mc TAKRI SIGN VIRAMA +116B7;CM # Mn TAKRI SIGN NUKTA +116B8;AL # Lo TAKRI LETTER ARCHAIC KHA +116C0..116C9;NU # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +11700..1171A;SA # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA +1171D..1171F;SA # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +11720..11721;SA # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA +11722..11725;SA # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU +11726;SA # Mc AHOM VOWEL SIGN E +11727..1172B;SA # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER +11730..11739;NU # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE +1173A..1173B;SA # No [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY +1173C..1173E;BA # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI +1173F;SA # So AHOM SYMBOL VI +11800..1182B;AL # Lo [44] DOGRA LETTER A..DOGRA LETTER RRA +1182C..1182E;CM # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II +1182F..11837;CM # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA +11838;CM # Mc DOGRA SIGN VISARGA +11839..1183A;CM # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA +1183B;AL # Po DOGRA ABBREVIATION SIGN +118A0..118DF;AL # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO +118E0..118E9;NU # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE +118EA..118F2;AL # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY +118FF;AL # Lo WARANG CITI OM +11900..11906;AL # Lo [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E +11909;AL # Lo DIVES AKURU LETTER O +1190C..11913;AL # Lo [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA +11915..11916;AL # Lo [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA +11918..1192F;AL # Lo [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA +11930..11935;CM # Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E +11937..11938;CM # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O +1193B..1193C;CM # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU +1193D;CM # Mc DIVES AKURU SIGN HALANTA +1193E;CM # Mn DIVES AKURU VIRAMA +1193F;AL # Lo DIVES AKURU PREFIXED NASAL SIGN +11940;CM # Mc DIVES AKURU MEDIAL YA +11941;AL # Lo DIVES AKURU INITIAL RA +11942;CM # Mc DIVES AKURU MEDIAL RA +11943;CM # Mn DIVES AKURU SIGN NUKTA +11944..11946;BA # Po [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK +11950..11959;NU # Nd [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE +119A0..119A7;AL # Lo [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR +119AA..119D0;AL # Lo [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA +119D1..119D3;CM # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II +119D4..119D7;CM # Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR +119DA..119DB;CM # Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI +119DC..119DF;CM # Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA +119E0;CM # Mn NANDINAGARI SIGN VIRAMA +119E1;AL # Lo NANDINAGARI SIGN AVAGRAHA +119E2;BB # Po NANDINAGARI SIGN SIDDHAM +119E3;AL # Lo NANDINAGARI HEADSTROKE +119E4;CM # Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E +11A00;AL # Lo ZANABAZAR SQUARE LETTER A +11A01..11A0A;CM # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A0B..11A32;AL # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A33..11A38;CM # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A39;CM # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3A;AL # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A3B..11A3E;CM # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A3F;BB # Po ZANABAZAR SQUARE INITIAL HEAD MARK +11A40;AL # Po ZANABAZAR SQUARE CLOSING HEAD MARK +11A41..11A44;BA # Po [4] ZANABAZAR SQUARE MARK TSHEG..ZANABAZAR SQUARE MARK LONG TSHEG +11A45;BB # Po ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK +11A46;AL # Po ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK +11A47;CM # Mn ZANABAZAR SQUARE SUBJOINER +11A50;AL # Lo SOYOMBO LETTER A +11A51..11A56;CM # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58;CM # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B;CM # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A5C..11A89;AL # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA +11A8A..11A96;CM # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97;CM # Mc SOYOMBO SIGN VISARGA +11A98..11A99;CM # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11A9A..11A9C;BA # Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD +11A9D;AL # Lo SOYOMBO MARK PLUTA +11A9E..11AA0;BB # Po [3] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO HEAD MARK WITH MOON AND SUN +11AA1..11AA2;BA # Po [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2 +11AC0..11AF8;AL # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11C00..11C08;AL # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E;AL # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C2F;CM # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36;CM # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D;CM # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E;CM # Mc BHAIKSUKI SIGN VISARGA +11C3F;CM # Mn BHAIKSUKI SIGN VIRAMA +11C40;AL # Lo BHAIKSUKI SIGN AVAGRAHA +11C41..11C45;BA # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 +11C50..11C59;NU # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11C5A..11C6C;AL # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK +11C70;BB # Po MARCHEN HEAD MARK +11C71;EX # Po MARCHEN MARK SHAD +11C72..11C8F;AL # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11C92..11CA7;CM # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9;CM # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0;CM # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1;CM # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3;CM # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4;CM # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6;CM # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D00..11D06;AL # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09;AL # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30;AL # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D31..11D36;CM # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A;CM # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D;CM # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45;CM # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D46;AL # Lo MASARAM GONDI REPHA +11D47;CM # Mn MASARAM GONDI RA-KARA +11D50..11D59;NU # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE +11D60..11D65;AL # Lo [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU +11D67..11D68;AL # Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI +11D6A..11D89;AL # Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA +11D8A..11D8E;CM # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU +11D90..11D91;CM # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI +11D93..11D94;CM # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU +11D95;CM # Mn GUNJALA GONDI SIGN ANUSVARA +11D96;CM # Mc GUNJALA GONDI SIGN VISARGA +11D97;CM # Mn GUNJALA GONDI VIRAMA +11D98;AL # Lo GUNJALA GONDI OM +11DA0..11DA9;NU # Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE +11EE0..11EF2;AL # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA +11EF3..11EF4;CM # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U +11EF5..11EF6;CM # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O +11EF7..11EF8;AL # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION +11FB0;AL # Lo LISU LETTER YHA +11FC0..11FD4;AL # No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH +11FD5..11FDC;AL # So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI +11FDD..11FE0;PO # Sc [4] TAMIL SIGN KAACU..TAMIL SIGN VARAAKAN +11FE1..11FF1;AL # So [17] TAMIL SIGN PAARAM..TAMIL SIGN VAKAIYARAA +11FFF;BA # Po TAMIL PUNCTUATION END OF TEXT +12000..12399;AL # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U +12400..1246E;AL # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM +12470..12474;BA # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON +12480..12543;AL # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU +13000..13257;AL # Lo [600] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH O006 +13258..1325A;OP # Lo [3] EGYPTIAN HIEROGLYPH O006A..EGYPTIAN HIEROGLYPH O006C +1325B..1325D;CL # Lo [3] EGYPTIAN HIEROGLYPH O006D..EGYPTIAN HIEROGLYPH O006F +1325E..13281;AL # Lo [36] EGYPTIAN HIEROGLYPH O007..EGYPTIAN HIEROGLYPH O033 +13282;CL # Lo EGYPTIAN HIEROGLYPH O033A +13283..13285;AL # Lo [3] EGYPTIAN HIEROGLYPH O034..EGYPTIAN HIEROGLYPH O036 +13286;OP # Lo EGYPTIAN HIEROGLYPH O036A +13287;CL # Lo EGYPTIAN HIEROGLYPH O036B +13288;OP # Lo EGYPTIAN HIEROGLYPH O036C +13289;CL # Lo EGYPTIAN HIEROGLYPH O036D +1328A..13378;AL # Lo [239] EGYPTIAN HIEROGLYPH O037..EGYPTIAN HIEROGLYPH V011 +13379;OP # Lo EGYPTIAN HIEROGLYPH V011A +1337A..1337B;CL # Lo [2] EGYPTIAN HIEROGLYPH V011B..EGYPTIAN HIEROGLYPH V011C +1337C..1342E;AL # Lo [179] EGYPTIAN HIEROGLYPH V012..EGYPTIAN HIEROGLYPH AA032 +13430..13436;GL # Cf [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE +13437;OP # Cf EGYPTIAN HIEROGLYPH BEGIN SEGMENT +13438;CL # Cf EGYPTIAN HIEROGLYPH END SEGMENT +14400..145CD;AL # Lo [462] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A409 +145CE;OP # Lo ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK +145CF;CL # Lo ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK +145D0..14646;AL # Lo [119] ANATOLIAN HIEROGLYPH A411..ANATOLIAN HIEROGLYPH A530 +16800..16A38;AL # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ +16A40..16A5E;AL # Lo [31] MRO LETTER TA..MRO LETTER TEK +16A60..16A69;NU # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE +16A6E..16A6F;BA # Po [2] MRO DANDA..MRO DOUBLE DANDA +16AD0..16AED;AL # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I +16AF0..16AF4;CM # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE +16AF5;BA # Po BASSA VAH FULL STOP +16B00..16B2F;AL # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU +16B30..16B36;CM # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM +16B37..16B39;BA # Po [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM +16B3A..16B3B;AL # Po [2] PAHAWH HMONG SIGN VOS THIAB..PAHAWH HMONG SIGN VOS FEEM +16B3C..16B3F;AL # So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB +16B40..16B43;AL # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16B44;BA # Po PAHAWH HMONG SIGN XAUS +16B45;AL # So PAHAWH HMONG SIGN CIM TSOV ROG +16B50..16B59;NU # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE +16B5B..16B61;AL # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS +16B63..16B77;AL # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS +16B7D..16B8F;AL # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16E40..16E7F;AL # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16E80..16E96;AL # No [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM +16E97..16E98;BA # Po [2] MEDEFAIDRIN COMMA..MEDEFAIDRIN FULL STOP +16E99..16E9A;AL # Po [2] MEDEFAIDRIN SYMBOL AIVA..MEDEFAIDRIN EXCLAMATION OH +16F00..16F4A;AL # Lo [75] MIAO LETTER PA..MIAO LETTER RTE +16F4F;CM # Mn MIAO SIGN CONSONANT MODIFIER BAR +16F50;AL # Lo MIAO LETTER NASALIZATION +16F51..16F87;CM # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI +16F8F..16F92;CM # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW +16F93..16F9F;AL # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 +16FE0..16FE1;NS # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +16FE2;NS # Po OLD CHINESE HOOK MARK +16FE3;NS # Lm OLD CHINESE ITERATION MARK +16FE4;GL # Mn KHITAN SMALL SCRIPT FILLER +16FF0..16FF1;CM # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY +17000..187F7;ID # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 +18800..18AFF;ID # Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768 +18B00..18CD5;AL # Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18D00..18D08;ID # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +1B000..1B0FF;ID # Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2 +1B100..1B11E;ID # Lo [31] HENTAIGANA LETTER RE-3..HENTAIGANA LETTER N-MU-MO-2 +1B150..1B152;CJ # Lo [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO +1B164..1B167;CJ # Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N +1B170..1B2FB;ID # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB +1BC00..1BC6A;AL # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M +1BC70..1BC7C;AL # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK +1BC80..1BC88;AL # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL +1BC90..1BC99;AL # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW +1BC9C;AL # So DUPLOYAN SIGN O WITH CROSS +1BC9D..1BC9E;CM # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1BC9F;BA # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1BCA0..1BCA3;CM # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP +1D000..1D0F5;AL # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO +1D100..1D126;AL # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2 +1D129..1D164;AL # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE +1D165..1D166;CM # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM +1D167..1D169;CM # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 +1D16A..1D16C;AL # So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3 +1D16D..1D172;CM # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 +1D173..1D17A;CM # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE +1D17B..1D182;CM # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE +1D183..1D184;AL # So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN +1D185..1D18B;CM # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE +1D18C..1D1A9;AL # So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH +1D1AA..1D1AD;CM # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1D1AE..1D1E8;AL # So [59] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KIEVAN FLAT SIGN +1D200..1D241;AL # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 +1D242..1D244;CM # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME +1D245;AL # So GREEK MUSICAL LEIMMA +1D2E0..1D2F3;AL # No [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN +1D300..1D356;AL # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING +1D360..1D378;AL # No [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE +1D400..1D454;AL # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G +1D456..1D49C;AL # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A +1D49E..1D49F;AL # Lu [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D +1D4A2;AL # Lu MATHEMATICAL SCRIPT CAPITAL G +1D4A5..1D4A6;AL # Lu [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K +1D4A9..1D4AC;AL # Lu [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q +1D4AE..1D4B9;AL # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D +1D4BB;AL # Ll MATHEMATICAL SCRIPT SMALL F +1D4BD..1D4C3;AL # Ll [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N +1D4C5..1D505;AL # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B +1D507..1D50A;AL # Lu [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G +1D50D..1D514;AL # Lu [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q +1D516..1D51C;AL # Lu [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y +1D51E..1D539;AL # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D53B..1D53E;AL # Lu [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D540..1D544;AL # Lu [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D546;AL # Lu MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D54A..1D550;AL # Lu [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D552..1D6A5;AL # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J +1D6A8..1D6C0;AL # Lu [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA +1D6C1;AL # Sm MATHEMATICAL BOLD NABLA +1D6C2..1D6DA;AL # Ll [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA +1D6DB;AL # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6DC..1D6FA;AL # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA +1D6FB;AL # Sm MATHEMATICAL ITALIC NABLA +1D6FC..1D714;AL # Ll [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA +1D715;AL # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D716..1D734;AL # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D735;AL # Sm MATHEMATICAL BOLD ITALIC NABLA +1D736..1D74E;AL # Ll [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D74F;AL # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D750..1D76E;AL # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D76F;AL # Sm MATHEMATICAL SANS-SERIF BOLD NABLA +1D770..1D788;AL # Ll [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D789;AL # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D78A..1D7A8;AL # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1D7A9;AL # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7AA..1D7C2;AL # Ll [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +1D7C3;AL # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL +1D7C4..1D7CB;AL # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA +1D7CE..1D7FF;NU # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE +1D800..1D9FF;AL # So [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD +1DA00..1DA36;CM # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN +1DA37..1DA3A;AL # So [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE +1DA3B..1DA6C;CM # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT +1DA6D..1DA74;AL # So [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING +1DA75;CM # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS +1DA76..1DA83;AL # So [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH +1DA84;CM # Mn SIGNWRITING LOCATION HEAD NECK +1DA85..1DA86;AL # So [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS +1DA87..1DA8A;BA # Po [4] SIGNWRITING COMMA..SIGNWRITING COLON +1DA8B;AL # Po SIGNWRITING PARENTHESIS +1DA9B..1DA9F;CM # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 +1DAA1..1DAAF;CM # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006;CM # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018;CM # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021;CM # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024;CM # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A;CM # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E100..1E12C;AL # Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W +1E130..1E136;CM # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D +1E137..1E13D;AL # Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER +1E140..1E149;NU # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE +1E14E;AL # Lo NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ +1E14F;AL # So NYIAKENG PUACHUE HMONG CIRCLED CA +1E2C0..1E2EB;AL # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH +1E2EC..1E2EF;CM # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI +1E2F0..1E2F9;NU # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE +1E2FF;PR # Sc WANCHO NGUN SIGN +1E800..1E8C4;AL # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON +1E8C7..1E8CF;AL # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE +1E8D0..1E8D6;CM # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E900..1E943;AL # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA +1E944..1E94A;CM # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +1E94B;AL # Lm ADLAM NASALIZATION MARK +1E950..1E959;NU # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95E..1E95F;OP # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK +1EC71..1ECAB;AL # No [59] INDIC SIYAQ NUMBER ONE..INDIC SIYAQ NUMBER PREFIXED NINE +1ECAC;PO # So INDIC SIYAQ PLACEHOLDER +1ECAD..1ECAF;AL # No [3] INDIC SIYAQ FRACTION ONE QUARTER..INDIC SIYAQ FRACTION THREE QUARTERS +1ECB0;PO # Sc INDIC SIYAQ RUPEE MARK +1ECB1..1ECB4;AL # No [4] INDIC SIYAQ NUMBER ALTERNATE ONE..INDIC SIYAQ ALTERNATE LAKH MARK +1ED01..1ED2D;AL # No [45] OTTOMAN SIYAQ NUMBER ONE..OTTOMAN SIYAQ NUMBER NINETY THOUSAND +1ED2E;AL # So OTTOMAN SIYAQ MARRATAN +1ED2F..1ED3D;AL # No [15] OTTOMAN SIYAQ ALTERNATE NUMBER TWO..OTTOMAN SIYAQ FRACTION ONE SIXTH +1EE00..1EE03;AL # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL +1EE05..1EE1F;AL # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF +1EE21..1EE22;AL # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM +1EE24;AL # Lo ARABIC MATHEMATICAL INITIAL HEH +1EE27;AL # Lo ARABIC MATHEMATICAL INITIAL HAH +1EE29..1EE32;AL # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF +1EE34..1EE37;AL # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH +1EE39;AL # Lo ARABIC MATHEMATICAL INITIAL DAD +1EE3B;AL # Lo ARABIC MATHEMATICAL INITIAL GHAIN +1EE42;AL # Lo ARABIC MATHEMATICAL TAILED JEEM +1EE47;AL # Lo ARABIC MATHEMATICAL TAILED HAH +1EE49;AL # Lo ARABIC MATHEMATICAL TAILED YEH +1EE4B;AL # Lo ARABIC MATHEMATICAL TAILED LAM +1EE4D..1EE4F;AL # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN +1EE51..1EE52;AL # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF +1EE54;AL # Lo ARABIC MATHEMATICAL TAILED SHEEN +1EE57;AL # Lo ARABIC MATHEMATICAL TAILED KHAH +1EE59;AL # Lo ARABIC MATHEMATICAL TAILED DAD +1EE5B;AL # Lo ARABIC MATHEMATICAL TAILED GHAIN +1EE5D;AL # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON +1EE5F;AL # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF +1EE61..1EE62;AL # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM +1EE64;AL # Lo ARABIC MATHEMATICAL STRETCHED HEH +1EE67..1EE6A;AL # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF +1EE6C..1EE72;AL # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF +1EE74..1EE77;AL # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH +1EE79..1EE7C;AL # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH +1EE7E;AL # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH +1EE80..1EE89;AL # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH +1EE8B..1EE9B;AL # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN +1EEA1..1EEA3;AL # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL +1EEA5..1EEA9;AL # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH +1EEAB..1EEBB;AL # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN +1EEF0..1EEF1;AL # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL +1F000..1F02B;ID # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK +1F02C..1F02F;ID # Cn [4] .. +1F030..1F093;ID # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 +1F094..1F09F;ID # Cn [12] .. +1F0A0..1F0AE;ID # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES +1F0AF..1F0B0;ID # Cn [2] .. +1F0B1..1F0BF;ID # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER +1F0C0;ID # Cn +1F0C1..1F0CF;ID # So [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER +1F0D0;ID # Cn +1F0D1..1F0F5;ID # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 +1F0F6..1F0FF;ID # Cn [10] .. +1F100..1F10C;AI # No [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO +1F10D..1F10F;ID # So [3] CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH +1F110..1F12D;AI # So [30] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED CD +1F12E..1F12F;AL # So [2] CIRCLED WZ..COPYLEFT SYMBOL +1F130..1F169;AI # So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F16A..1F16C;AL # So [3] RAISED MC SIGN..RAISED MR SIGN +1F16D..1F16F;ID # So [3] CIRCLED CC..CIRCLED HUMAN FIGURE +1F170..1F1AC;AI # So [61] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VOD +1F1AD;ID # So MASK WORK SYMBOL +1F1AE..1F1E5;ID # Cn [56] .. +1F1E6..1F1FF;RI # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z +1F200..1F202;ID # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA +1F203..1F20F;ID # Cn [13] .. +1F210..1F23B;ID # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D +1F23C..1F23F;ID # Cn [4] .. +1F240..1F248;ID # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 +1F249..1F24F;ID # Cn [7] .. +1F250..1F251;ID # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT +1F252..1F25F;ID # Cn [14] .. +1F260..1F265;ID # So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI +1F266..1F2FF;ID # Cn [154] .. +1F300..1F384;ID # So [133] CYCLONE..CHRISTMAS TREE +1F385;EB # So FATHER CHRISTMAS +1F386..1F39B;ID # So [22] FIREWORKS..CONTROL KNOBS +1F39C..1F39D;AL # So [2] BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES +1F39E..1F3B4;ID # So [23] FILM FRAMES..FLOWER PLAYING CARDS +1F3B5..1F3B6;AL # So [2] MUSICAL NOTE..MULTIPLE MUSICAL NOTES +1F3B7..1F3BB;ID # So [5] SAXOPHONE..VIOLIN +1F3BC;AL # So MUSICAL SCORE +1F3BD..1F3C1;ID # So [5] RUNNING SHIRT WITH SASH..CHEQUERED FLAG +1F3C2..1F3C4;EB # So [3] SNOWBOARDER..SURFER +1F3C5..1F3C6;ID # So [2] SPORTS MEDAL..TROPHY +1F3C7;EB # So HORSE RACING +1F3C8..1F3C9;ID # So [2] AMERICAN FOOTBALL..RUGBY FOOTBALL +1F3CA..1F3CC;EB # So [3] SWIMMER..GOLFER +1F3CD..1F3FA;ID # So [46] RACING MOTORCYCLE..AMPHORA +1F3FB..1F3FF;EM # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 +1F400..1F441;ID # So [66] RAT..EYE +1F442..1F443;EB # So [2] EAR..NOSE +1F444..1F445;ID # So [2] MOUTH..TONGUE +1F446..1F450;EB # So [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN +1F451..1F465;ID # So [21] CROWN..BUSTS IN SILHOUETTE +1F466..1F478;EB # So [19] BOY..PRINCESS +1F479..1F47B;ID # So [3] JAPANESE OGRE..GHOST +1F47C;EB # So BABY ANGEL +1F47D..1F480;ID # So [4] EXTRATERRESTRIAL ALIEN..SKULL +1F481..1F483;EB # So [3] INFORMATION DESK PERSON..DANCER +1F484;ID # So LIPSTICK +1F485..1F487;EB # So [3] NAIL POLISH..HAIRCUT +1F488..1F48E;ID # So [7] BARBER POLE..GEM STONE +1F48F;EB # So KISS +1F490;ID # So BOUQUET +1F491;EB # So COUPLE WITH HEART +1F492..1F49F;ID # So [14] WEDDING..HEART DECORATION +1F4A0;AL # So DIAMOND SHAPE WITH A DOT INSIDE +1F4A1;ID # So ELECTRIC LIGHT BULB +1F4A2;AL # So ANGER SYMBOL +1F4A3;ID # So BOMB +1F4A4;AL # So SLEEPING SYMBOL +1F4A5..1F4A9;ID # So [5] COLLISION SYMBOL..PILE OF POO +1F4AA;EB # So FLEXED BICEPS +1F4AB..1F4AE;ID # So [4] DIZZY SYMBOL..WHITE FLOWER +1F4AF;AL # So HUNDRED POINTS SYMBOL +1F4B0;ID # So MONEY BAG +1F4B1..1F4B2;AL # So [2] CURRENCY EXCHANGE..HEAVY DOLLAR SIGN +1F4B3..1F4FF;ID # So [77] CREDIT CARD..PRAYER BEADS +1F500..1F506;AL # So [7] TWISTED RIGHTWARDS ARROWS..HIGH BRIGHTNESS SYMBOL +1F507..1F516;ID # So [16] SPEAKER WITH CANCELLATION STROKE..BOOKMARK +1F517..1F524;AL # So [14] LINK SYMBOL..INPUT SYMBOL FOR LATIN LETTERS +1F525..1F531;ID # So [13] FIRE..TRIDENT EMBLEM +1F532..1F549;AL # So [24] BLACK SQUARE BUTTON..OM SYMBOL +1F54A..1F573;ID # So [42] DOVE OF PEACE..HOLE +1F574..1F575;EB # So [2] MAN IN BUSINESS SUIT LEVITATING..SLEUTH OR SPY +1F576..1F579;ID # So [4] DARK SUNGLASSES..JOYSTICK +1F57A;EB # So MAN DANCING +1F57B..1F58F;ID # So [21] LEFT HAND TELEPHONE RECEIVER..TURNED OK HAND SIGN +1F590;EB # So RAISED HAND WITH FINGERS SPLAYED +1F591..1F594;ID # So [4] REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND +1F595..1F596;EB # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS +1F597..1F5D3;ID # So [61] WHITE DOWN POINTING LEFT HAND INDEX..SPIRAL CALENDAR PAD +1F5D4..1F5DB;AL # So [8] DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL +1F5DC..1F5F3;ID # So [24] COMPRESSION..BALLOT BOX WITH BALLOT +1F5F4..1F5F9;AL # So [6] BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK +1F5FA..1F5FF;ID # So [6] WORLD MAP..MOYAI +1F600..1F644;ID # So [69] GRINNING FACE..FACE WITH ROLLING EYES +1F645..1F647;EB # So [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY +1F648..1F64A;ID # So [3] SEE-NO-EVIL MONKEY..SPEAK-NO-EVIL MONKEY +1F64B..1F64F;EB # So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS +1F650..1F675;AL # So [38] NORTH WEST POINTING LEAF..SWASH AMPERSAND ORNAMENT +1F676..1F678;QU # So [3] SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT..SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT +1F679..1F67B;NS # So [3] HEAVY INTERROBANG ORNAMENT..HEAVY SANS-SERIF INTERROBANG ORNAMENT +1F67C..1F67F;AL # So [4] VERY HEAVY SOLIDUS..REVERSE CHECKER BOARD +1F680..1F6A2;ID # So [35] ROCKET..SHIP +1F6A3;EB # So ROWBOAT +1F6A4..1F6B3;ID # So [16] SPEEDBOAT..NO BICYCLES +1F6B4..1F6B6;EB # So [3] BICYCLIST..PEDESTRIAN +1F6B7..1F6BF;ID # So [9] NO PEDESTRIANS..SHOWER +1F6C0;EB # So BATH +1F6C1..1F6CB;ID # So [11] BATHTUB..COUCH AND LAMP +1F6CC;EB # So SLEEPING ACCOMMODATION +1F6CD..1F6D7;ID # So [11] SHOPPING BAGS..ELEVATOR +1F6D8..1F6DF;ID # Cn [8] .. +1F6E0..1F6EC;ID # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING +1F6ED..1F6EF;ID # Cn [3] .. +1F6F0..1F6FC;ID # So [13] SATELLITE..ROLLER SKATE +1F6FD..1F6FF;ID # Cn [3] .. +1F700..1F773;AL # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE +1F774..1F77F;ID # Cn [12] .. +1F780..1F7D4;AL # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR +1F7D5..1F7D8;ID # So [4] CIRCLED TRIANGLE..NEGATIVE CIRCLED SQUARE +1F7D9..1F7DF;ID # Cn [7] .. +1F7E0..1F7EB;ID # So [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE +1F7EC..1F7FF;ID # Cn [20] .. +1F800..1F80B;AL # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F80C..1F80F;ID # Cn [4] .. +1F810..1F847;AL # So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW +1F848..1F84F;ID # Cn [8] .. +1F850..1F859;AL # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW +1F85A..1F85F;ID # Cn [6] .. +1F860..1F887;AL # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW +1F888..1F88F;ID # Cn [8] .. +1F890..1F8AD;AL # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS +1F8AE..1F8AF;ID # Cn [2] .. +1F8B0..1F8B1;ID # So [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST +1F8B2..1F8FF;ID # Cn [78] .. +1F900..1F90B;AL # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT +1F90C;EB # So PINCHED FINGERS +1F90D..1F90E;ID # So [2] WHITE HEART..BROWN HEART +1F90F;EB # So PINCHING HAND +1F910..1F917;ID # So [8] ZIPPER-MOUTH FACE..HUGGING FACE +1F918..1F91F;EB # So [8] SIGN OF THE HORNS..I LOVE YOU HAND SIGN +1F920..1F925;ID # So [6] FACE WITH COWBOY HAT..LYING FACE +1F926;EB # So FACE PALM +1F927..1F92F;ID # So [9] SNEEZING FACE..SHOCKED FACE WITH EXPLODING HEAD +1F930..1F939;EB # So [10] PREGNANT WOMAN..JUGGLING +1F93A..1F93B;ID # So [2] FENCER..MODERN PENTATHLON +1F93C..1F93E;EB # So [3] WRESTLERS..HANDBALL +1F93F..1F976;ID # So [56] DIVING MASK..FREEZING FACE +1F977;EB # So NINJA +1F978;ID # So DISGUISED FACE +1F979;ID # Cn +1F97A..1F9B4;ID # So [59] FACE WITH PLEADING EYES..BONE +1F9B5..1F9B6;EB # So [2] LEG..FOOT +1F9B7;ID # So TOOTH +1F9B8..1F9B9;EB # So [2] SUPERHERO..SUPERVILLAIN +1F9BA;ID # So SAFETY VEST +1F9BB;EB # So EAR WITH HEARING AID +1F9BC..1F9CB;ID # So [16] MOTORIZED WHEELCHAIR..BUBBLE TEA +1F9CC;ID # Cn +1F9CD..1F9CF;EB # So [3] STANDING PERSON..DEAF PERSON +1F9D0;ID # So FACE WITH MONOCLE +1F9D1..1F9DD;EB # So [13] ADULT..ELF +1F9DE..1F9FF;ID # So [34] GENIE..NAZAR AMULET +1FA00..1FA53;AL # So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP +1FA54..1FA5F;ID # Cn [12] .. +1FA60..1FA6D;ID # So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER +1FA6E..1FA6F;ID # Cn [2] .. +1FA70..1FA74;ID # So [5] BALLET SHOES..THONG SANDAL +1FA75..1FA77;ID # Cn [3] .. +1FA78..1FA7A;ID # So [3] DROP OF BLOOD..STETHOSCOPE +1FA7B..1FA7F;ID # Cn [5] .. +1FA80..1FA86;ID # So [7] YO-YO..NESTING DOLLS +1FA87..1FA8F;ID # Cn [9] .. +1FA90..1FAA8;ID # So [25] RINGED PLANET..ROCK +1FAA9..1FAAF;ID # Cn [7] .. +1FAB0..1FAB6;ID # So [7] FLY..FEATHER +1FAB7..1FABF;ID # Cn [9] .. +1FAC0..1FAC2;ID # So [3] ANATOMICAL HEART..PEOPLE HUGGING +1FAC3..1FACF;ID # Cn [13] .. +1FAD0..1FAD6;ID # So [7] BLUEBERRIES..TEAPOT +1FAD7..1FAFF;ID # Cn [41] .. +1FB00..1FB92;AL # So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK +1FB94..1FBCA;AL # So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON +1FBF0..1FBF9;NU # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE +1FC00..1FFFD;ID # Cn [1022] .. +20000..2A6DD;ID # Lo [42718] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DD +2A6DE..2A6FF;ID # Cn [34] .. +2A700..2B734;ID # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 +2B735..2B73F;ID # Cn [11] .. +2B740..2B81D;ID # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D +2B81E..2B81F;ID # Cn [2] .. +2B820..2CEA1;ID # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2CEA2..2CEAF;ID # Cn [14] .. +2CEB0..2EBE0;ID # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 +2EBE1..2F7FF;ID # Cn [3103] .. +2F800..2FA1D;ID # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D +2FA1E..2FA1F;ID # Cn [2] .. +2FA20..2FFFD;ID # Cn [1502] .. +30000..3134A;ID # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A +3134B..3FFFD;ID # Cn [60595] .. +E0001;CM # Cf LANGUAGE TAG +E0020..E007F;CM # Cf [96] TAG SPACE..CANCEL TAG +E0100..E01EF;CM # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 +F0000..FFFFD;XX # Co [65534] .. +100000..10FFFD;XX # Co [65534] .. + +# EOF diff --git a/third_party/web_unicode/properties/WordBreakProperty.txt b/third_party/web_unicode/properties/WordBreakProperty.txt new file mode 100644 index 0000000000000..36d1438c26c9c --- /dev/null +++ b/third_party/web_unicode/properties/WordBreakProperty.txt @@ -0,0 +1,1397 @@ +# WordBreakProperty-13.0.0.txt +# Date: 2020-01-22, 00:07:44 GMT +# © 2020 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ + +# ================================================ + +# Property: Word_Break + +# All code points not explicitly listed for Word_Break +# have the value Other (XX). + +# @missing: 0000..10FFFF; Other + +# ================================================ + +0022 ; Double_Quote # Po QUOTATION MARK + +# Total code points: 1 + +# ================================================ + +0027 ; Single_Quote # Po APOSTROPHE + +# Total code points: 1 + +# ================================================ + +05D0..05EA ; Hebrew_Letter # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV +05EF..05F2 ; Hebrew_Letter # Lo [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD +FB1D ; Hebrew_Letter # Lo HEBREW LETTER YOD WITH HIRIQ +FB1F..FB28 ; Hebrew_Letter # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV +FB2A..FB36 ; Hebrew_Letter # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH +FB38..FB3C ; Hebrew_Letter # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH +FB3E ; Hebrew_Letter # Lo HEBREW LETTER MEM WITH DAGESH +FB40..FB41 ; Hebrew_Letter # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH +FB43..FB44 ; Hebrew_Letter # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH +FB46..FB4F ; Hebrew_Letter # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED + +# Total code points: 75 + +# ================================================ + +000D ; CR # Cc + +# Total code points: 1 + +# ================================================ + +000A ; LF # Cc + +# Total code points: 1 + +# ================================================ + +000B..000C ; Newline # Cc [2] .. +0085 ; Newline # Cc +2028 ; Newline # Zl LINE SEPARATOR +2029 ; Newline # Zp PARAGRAPH SEPARATOR + +# Total code points: 5 + +# ================================================ + +0300..036F ; Extend # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X +0483..0487 ; Extend # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE +0488..0489 ; Extend # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN +0591..05BD ; Extend # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG +05BF ; Extend # Mn HEBREW POINT RAFE +05C1..05C2 ; Extend # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C4..05C5 ; Extend # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT +05C7 ; Extend # Mn HEBREW POINT QAMATS QATAN +0610..061A ; Extend # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA +064B..065F ; Extend # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW +0670 ; Extend # Mn ARABIC LETTER SUPERSCRIPT ALEF +06D6..06DC ; Extend # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN +06DF..06E4 ; Extend # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA +06E7..06E8 ; Extend # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON +06EA..06ED ; Extend # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM +0711 ; Extend # Mn SYRIAC LETTER SUPERSCRIPT ALAPH +0730..074A ; Extend # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH +07A6..07B0 ; Extend # Mn [11] THAANA ABAFILI..THAANA SUKUN +07EB..07F3 ; Extend # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE +07FD ; Extend # Mn NKO DANTAYALAN +0816..0819 ; Extend # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH +081B..0823 ; Extend # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A +0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U +0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA +0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +08D3..08E1 ; Extend # Mn [15] ARABIC SMALL LOW WAW..ARABIC SMALL HIGH SIGN SAFHA +08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA +0903 ; Extend # Mc DEVANAGARI SIGN VISARGA +093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE +093B ; Extend # Mc DEVANAGARI VOWEL SIGN OOE +093C ; Extend # Mn DEVANAGARI SIGN NUKTA +093E..0940 ; Extend # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II +0941..0948 ; Extend # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI +0949..094C ; Extend # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU +094D ; Extend # Mn DEVANAGARI SIGN VIRAMA +094E..094F ; Extend # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW +0951..0957 ; Extend # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE +0962..0963 ; Extend # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL +0981 ; Extend # Mn BENGALI SIGN CANDRABINDU +0982..0983 ; Extend # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA +09BC ; Extend # Mn BENGALI SIGN NUKTA +09BE..09C0 ; Extend # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II +09C1..09C4 ; Extend # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR +09C7..09C8 ; Extend # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI +09CB..09CC ; Extend # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU +09CD ; Extend # Mn BENGALI SIGN VIRAMA +09D7 ; Extend # Mc BENGALI AU LENGTH MARK +09E2..09E3 ; Extend # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL +09FE ; Extend # Mn BENGALI SANDHI MARK +0A01..0A02 ; Extend # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI +0A03 ; Extend # Mc GURMUKHI SIGN VISARGA +0A3C ; Extend # Mn GURMUKHI SIGN NUKTA +0A3E..0A40 ; Extend # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II +0A41..0A42 ; Extend # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU +0A47..0A48 ; Extend # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI +0A4B..0A4D ; Extend # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA +0A51 ; Extend # Mn GURMUKHI SIGN UDAAT +0A70..0A71 ; Extend # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK +0A75 ; Extend # Mn GURMUKHI SIGN YAKASH +0A81..0A82 ; Extend # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA +0A83 ; Extend # Mc GUJARATI SIGN VISARGA +0ABC ; Extend # Mn GUJARATI SIGN NUKTA +0ABE..0AC0 ; Extend # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II +0AC1..0AC5 ; Extend # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E +0AC7..0AC8 ; Extend # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI +0AC9 ; Extend # Mc GUJARATI VOWEL SIGN CANDRA O +0ACB..0ACC ; Extend # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU +0ACD ; Extend # Mn GUJARATI SIGN VIRAMA +0AE2..0AE3 ; Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AFA..0AFF ; Extend # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE +0B01 ; Extend # Mn ORIYA SIGN CANDRABINDU +0B02..0B03 ; Extend # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA +0B3C ; Extend # Mn ORIYA SIGN NUKTA +0B3E ; Extend # Mc ORIYA VOWEL SIGN AA +0B3F ; Extend # Mn ORIYA VOWEL SIGN I +0B40 ; Extend # Mc ORIYA VOWEL SIGN II +0B41..0B44 ; Extend # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR +0B47..0B48 ; Extend # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI +0B4B..0B4C ; Extend # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU +0B4D ; Extend # Mn ORIYA SIGN VIRAMA +0B55..0B56 ; Extend # Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK +0B57 ; Extend # Mc ORIYA AU LENGTH MARK +0B62..0B63 ; Extend # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL +0B82 ; Extend # Mn TAMIL SIGN ANUSVARA +0BBE..0BBF ; Extend # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I +0BC0 ; Extend # Mn TAMIL VOWEL SIGN II +0BC1..0BC2 ; Extend # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU +0BC6..0BC8 ; Extend # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI +0BCA..0BCC ; Extend # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU +0BCD ; Extend # Mn TAMIL SIGN VIRAMA +0BD7 ; Extend # Mc TAMIL AU LENGTH MARK +0C00 ; Extend # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE +0C01..0C03 ; Extend # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C04 ; Extend # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE +0C3E..0C40 ; Extend # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II +0C41..0C44 ; Extend # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR +0C46..0C48 ; Extend # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI +0C4A..0C4D ; Extend # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA +0C55..0C56 ; Extend # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK +0C62..0C63 ; Extend # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL +0C81 ; Extend # Mn KANNADA SIGN CANDRABINDU +0C82..0C83 ; Extend # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA +0CBC ; Extend # Mn KANNADA SIGN NUKTA +0CBE ; Extend # Mc KANNADA VOWEL SIGN AA +0CBF ; Extend # Mn KANNADA VOWEL SIGN I +0CC0..0CC4 ; Extend # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR +0CC6 ; Extend # Mn KANNADA VOWEL SIGN E +0CC7..0CC8 ; Extend # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI +0CCA..0CCB ; Extend # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO +0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA +0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL +0D00..0D01 ; Extend # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU +0D02..0D03 ; Extend # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D3B..0D3C ; Extend # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA +0D3E..0D40 ; Extend # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II +0D41..0D44 ; Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR +0D46..0D48 ; Extend # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +0D4A..0D4C ; Extend # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU +0D4D ; Extend # Mn MALAYALAM SIGN VIRAMA +0D57 ; Extend # Mc MALAYALAM AU LENGTH MARK +0D62..0D63 ; Extend # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL +0D81 ; Extend # Mn SINHALA SIGN CANDRABINDU +0D82..0D83 ; Extend # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA +0DCA ; Extend # Mn SINHALA SIGN AL-LAKUNA +0DCF..0DD1 ; Extend # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA +0DD2..0DD4 ; Extend # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6 ; Extend # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8..0DDF ; Extend # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DF2..0DF3 ; Extend # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +0E31 ; Extend # Mn THAI CHARACTER MAI HAN-AKAT +0E34..0E3A ; Extend # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU +0E47..0E4E ; Extend # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN +0EB1 ; Extend # Mn LAO VOWEL SIGN MAI KAN +0EB4..0EBC ; Extend # Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO +0EC8..0ECD ; Extend # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA +0F18..0F19 ; Extend # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F35 ; Extend # Mn TIBETAN MARK NGAS BZUNG NYI ZLA +0F37 ; Extend # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F39 ; Extend # Mn TIBETAN MARK TSA -PHRU +0F3E..0F3F ; Extend # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES +0F71..0F7E ; Extend # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO +0F7F ; Extend # Mc TIBETAN SIGN RNAM BCAD +0F80..0F84 ; Extend # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA +0F86..0F87 ; Extend # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS +0F8D..0F97 ; Extend # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA +0F99..0FBC ; Extend # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA +0FC6 ; Extend # Mn TIBETAN SYMBOL PADMA GDAN +102B..102C ; Extend # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA +102D..1030 ; Extend # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU +1031 ; Extend # Mc MYANMAR VOWEL SIGN E +1032..1037 ; Extend # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW +1038 ; Extend # Mc MYANMAR SIGN VISARGA +1039..103A ; Extend # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT +103B..103C ; Extend # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA +103D..103E ; Extend # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA +1056..1057 ; Extend # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR +1058..1059 ; Extend # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL +105E..1060 ; Extend # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA +1062..1064 ; Extend # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO +1067..106D ; Extend # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5 +1071..1074 ; Extend # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE +1082 ; Extend # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA +1083..1084 ; Extend # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E +1085..1086 ; Extend # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y +1087..108C ; Extend # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3 +108D ; Extend # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE +108F ; Extend # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5 +109A..109C ; Extend # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A +109D ; Extend # Mn MYANMAR VOWEL SIGN AITON AI +135D..135F ; Extend # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK +1712..1714 ; Extend # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA +1732..1734 ; Extend # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD +1752..1753 ; Extend # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U +1772..1773 ; Extend # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U +17B4..17B5 ; Extend # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA +17B6 ; Extend # Mc KHMER VOWEL SIGN AA +17B7..17BD ; Extend # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA +17BE..17C5 ; Extend # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU +17C6 ; Extend # Mn KHMER SIGN NIKAHIT +17C7..17C8 ; Extend # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU +17C9..17D3 ; Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT +17DD ; Extend # Mn KHMER SIGN ATTHACAN +180B..180D ; Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +1885..1886 ; Extend # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +18A9 ; Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA +1920..1922 ; Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U +1923..1926 ; Extend # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU +1927..1928 ; Extend # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O +1929..192B ; Extend # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA +1930..1931 ; Extend # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA +1932 ; Extend # Mn LIMBU SMALL LETTER ANUSVARA +1933..1938 ; Extend # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA +1939..193B ; Extend # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I +1A17..1A18 ; Extend # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U +1A19..1A1A ; Extend # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O +1A1B ; Extend # Mn BUGINESE VOWEL SIGN AE +1A55 ; Extend # Mc TAI THAM CONSONANT SIGN MEDIAL RA +1A56 ; Extend # Mn TAI THAM CONSONANT SIGN MEDIAL LA +1A57 ; Extend # Mc TAI THAM CONSONANT SIGN LA TANG LAI +1A58..1A5E ; Extend # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA +1A60 ; Extend # Mn TAI THAM SIGN SAKOT +1A61 ; Extend # Mc TAI THAM VOWEL SIGN A +1A62 ; Extend # Mn TAI THAM VOWEL SIGN MAI SAT +1A63..1A64 ; Extend # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA +1A65..1A6C ; Extend # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW +1A6D..1A72 ; Extend # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI +1A73..1A7C ; Extend # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN +1A7F ; Extend # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT +1AB0..1ABD ; Extend # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW +1ABE ; Extend # Me COMBINING PARENTHESES OVERLAY +1ABF..1AC0 ; Extend # Mn [2] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER TURNED W BELOW +1B00..1B03 ; Extend # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG +1B04 ; Extend # Mc BALINESE SIGN BISAH +1B34 ; Extend # Mn BALINESE SIGN REREKAN +1B35 ; Extend # Mc BALINESE VOWEL SIGN TEDUNG +1B36..1B3A ; Extend # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA +1B3B ; Extend # Mc BALINESE VOWEL SIGN RA REPA TEDUNG +1B3C ; Extend # Mn BALINESE VOWEL SIGN LA LENGA +1B3D..1B41 ; Extend # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG +1B42 ; Extend # Mn BALINESE VOWEL SIGN PEPET +1B43..1B44 ; Extend # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG +1B6B..1B73 ; Extend # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG +1B80..1B81 ; Extend # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR +1B82 ; Extend # Mc SUNDANESE SIGN PANGWISAD +1BA1 ; Extend # Mc SUNDANESE CONSONANT SIGN PAMINGKAL +1BA2..1BA5 ; Extend # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU +1BA6..1BA7 ; Extend # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG +1BA8..1BA9 ; Extend # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG +1BAA ; Extend # Mc SUNDANESE SIGN PAMAAEH +1BAB..1BAD ; Extend # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BE6 ; Extend # Mn BATAK SIGN TOMPI +1BE7 ; Extend # Mc BATAK VOWEL SIGN E +1BE8..1BE9 ; Extend # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE +1BEA..1BEC ; Extend # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O +1BED ; Extend # Mn BATAK VOWEL SIGN KARO O +1BEE ; Extend # Mc BATAK VOWEL SIGN U +1BEF..1BF1 ; Extend # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H +1BF2..1BF3 ; Extend # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN +1C24..1C2B ; Extend # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU +1C2C..1C33 ; Extend # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T +1C34..1C35 ; Extend # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG +1C36..1C37 ; Extend # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA +1CD0..1CD2 ; Extend # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA +1CD4..1CE0 ; Extend # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA +1CE1 ; Extend # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA +1CE2..1CE8 ; Extend # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL +1CED ; Extend # Mn VEDIC SIGN TIRYAK +1CF4 ; Extend # Mn VEDIC TONE CANDRA ABOVE +1CF7 ; Extend # Mc VEDIC SIGN ATIKRAMA +1CF8..1CF9 ; Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE +1DC0..1DF9 ; Extend # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF ; Extend # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +200C ; Extend # Cf ZERO WIDTH NON-JOINER +20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE +20DD..20E0 ; Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH +20E1 ; Extend # Mn COMBINING LEFT RIGHT ARROW ABOVE +20E2..20E4 ; Extend # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE +20E5..20F0 ; Extend # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE +2CEF..2CF1 ; Extend # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS +2D7F ; Extend # Mn TIFINAGH CONSONANT JOINER +2DE0..2DFF ; Extend # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS +302A..302D ; Extend # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK +302E..302F ; Extend # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK +3099..309A ; Extend # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +A66F ; Extend # Mn COMBINING CYRILLIC VZMET +A670..A672 ; Extend # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN +A674..A67D ; Extend # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK +A69E..A69F ; Extend # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E +A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS +A802 ; Extend # Mn SYLOTI NAGRI SIGN DVISVARA +A806 ; Extend # Mn SYLOTI NAGRI SIGN HASANTA +A80B ; Extend # Mn SYLOTI NAGRI SIGN ANUSVARA +A823..A824 ; Extend # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I +A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E +A827 ; Extend # Mc SYLOTI NAGRI VOWEL SIGN OO +A82C ; Extend # Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA +A880..A881 ; Extend # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA +A8B4..A8C3 ; Extend # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU +A8C4..A8C5 ; Extend # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU +A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA +A8FF ; Extend # Mn DEVANAGARI VOWEL SIGN AY +A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU +A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R +A952..A953 ; Extend # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA +A980..A982 ; Extend # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR +A983 ; Extend # Mc JAVANESE SIGN WIGNYAN +A9B3 ; Extend # Mn JAVANESE SIGN CECAK TELU +A9B4..A9B5 ; Extend # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG +A9B6..A9B9 ; Extend # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT +A9BA..A9BB ; Extend # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE +A9BC..A9BD ; Extend # Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET +A9BE..A9C0 ; Extend # Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON +A9E5 ; Extend # Mn MYANMAR SIGN SHAN SAW +AA29..AA2E ; Extend # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE +AA2F..AA30 ; Extend # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI +AA31..AA32 ; Extend # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE +AA33..AA34 ; Extend # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA +AA35..AA36 ; Extend # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA +AA43 ; Extend # Mn CHAM CONSONANT SIGN FINAL NG +AA4C ; Extend # Mn CHAM CONSONANT SIGN FINAL M +AA4D ; Extend # Mc CHAM CONSONANT SIGN FINAL H +AA7B ; Extend # Mc MYANMAR SIGN PAO KAREN TONE +AA7C ; Extend # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D ; Extend # Mc MYANMAR SIGN TAI LAING TONE-5 +AAB0 ; Extend # Mn TAI VIET MAI KANG +AAB2..AAB4 ; Extend # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U +AAB7..AAB8 ; Extend # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA +AABE..AABF ; Extend # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK +AAC1 ; Extend # Mn TAI VIET TONE MAI THO +AAEB ; Extend # Mc MEETEI MAYEK VOWEL SIGN II +AAEC..AAED ; Extend # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI +AAEE..AAEF ; Extend # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU +AAF5 ; Extend # Mc MEETEI MAYEK VOWEL SIGN VISARGA +AAF6 ; Extend # Mn MEETEI MAYEK VIRAMA +ABE3..ABE4 ; Extend # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP +ABE5 ; Extend # Mn MEETEI MAYEK VOWEL SIGN ANAP +ABE6..ABE7 ; Extend # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP +ABE8 ; Extend # Mn MEETEI MAYEK VOWEL SIGN UNAP +ABE9..ABEA ; Extend # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG +ABEC ; Extend # Mc MEETEI MAYEK LUM IYEK +ABED ; Extend # Mn MEETEI MAYEK APUN IYEK +FB1E ; Extend # Mn HEBREW POINT JUDEO-SPANISH VARIKA +FE00..FE0F ; Extend # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 +FE20..FE2F ; Extend # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF +FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +101FD ; Extend # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE +102E0 ; Extend # Mn COPTIC EPACT THOUSANDS MARK +10376..1037A ; Extend # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII +10A01..10A03 ; Extend # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R +10A05..10A06 ; Extend # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O +10A0C..10A0F ; Extend # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA +10A38..10A3A ; Extend # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW +10A3F ; Extend # Mn KHAROSHTHI VIRAMA +10AE5..10AE6 ; Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW +10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10EAB..10EAC ; Extend # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK +10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW +11000 ; Extend # Mc BRAHMI SIGN CANDRABINDU +11001 ; Extend # Mn BRAHMI SIGN ANUSVARA +11002 ; Extend # Mc BRAHMI SIGN VISARGA +11038..11046 ; Extend # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA +1107F..11081 ; Extend # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA +11082 ; Extend # Mc KAITHI SIGN VISARGA +110B0..110B2 ; Extend # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II +110B3..110B6 ; Extend # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI +110B7..110B8 ; Extend # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU +110B9..110BA ; Extend # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA +11100..11102 ; Extend # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA +11127..1112B ; Extend # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU +1112C ; Extend # Mc CHAKMA VOWEL SIGN E +1112D..11134 ; Extend # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA +11145..11146 ; Extend # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI +11173 ; Extend # Mn MAHAJANI SIGN NUKTA +11180..11181 ; Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA +11182 ; Extend # Mc SHARADA SIGN VISARGA +111B3..111B5 ; Extend # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II +111B6..111BE ; Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O +111BF..111C0 ; Extend # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA +111C9..111CC ; Extend # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK +111CE ; Extend # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E +111CF ; Extend # Mn SHARADA SIGN INVERTED CANDRABINDU +1122C..1122E ; Extend # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II +1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +11232..11233 ; Extend # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU +11234 ; Extend # Mn KHOJKI SIGN ANUSVARA +11235 ; Extend # Mc KHOJKI SIGN VIRAMA +11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +1123E ; Extend # Mn KHOJKI SIGN SUKUN +112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA +112E0..112E2 ; Extend # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II +112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA +11300..11301 ; Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU +11302..11303 ; Extend # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +1133B..1133C ; Extend # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA +1133E..1133F ; Extend # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I +11340 ; Extend # Mn GRANTHA VOWEL SIGN II +11341..11344 ; Extend # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR +11347..11348 ; Extend # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +1134B..1134D ; Extend # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +11357 ; Extend # Mc GRANTHA AU LENGTH MARK +11362..11363 ; Extend # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11366..1136C ; Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +11370..11374 ; Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11435..11437 ; Extend # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441 ; Extend # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445 ; Extend # Mc NEWA SIGN VISARGA +11446 ; Extend # Mn NEWA SIGN NUKTA +1145E ; Extend # Mn NEWA SANDHI MARK +114B0..114B2 ; Extend # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II +114B3..114B8 ; Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL +114B9 ; Extend # Mc TIRHUTA VOWEL SIGN E +114BA ; Extend # Mn TIRHUTA VOWEL SIGN SHORT E +114BB..114BE ; Extend # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU +114BF..114C0 ; Extend # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA +114C1 ; Extend # Mc TIRHUTA SIGN VISARGA +114C2..114C3 ; Extend # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +115AF..115B1 ; Extend # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II +115B2..115B5 ; Extend # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR +115B8..115BB ; Extend # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +115BC..115BD ; Extend # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +115BE ; Extend # Mc SIDDHAM SIGN VISARGA +115BF..115C0 ; Extend # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA +115DC..115DD ; Extend # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU +11630..11632 ; Extend # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II +11633..1163A ; Extend # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI +1163B..1163C ; Extend # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU +1163D ; Extend # Mn MODI SIGN ANUSVARA +1163E ; Extend # Mc MODI SIGN VISARGA +1163F..11640 ; Extend # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA +116AB ; Extend # Mn TAKRI SIGN ANUSVARA +116AC ; Extend # Mc TAKRI SIGN VISARGA +116AD ; Extend # Mn TAKRI VOWEL SIGN AA +116AE..116AF ; Extend # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II +116B0..116B5 ; Extend # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +116B6 ; Extend # Mc TAKRI SIGN VIRAMA +116B7 ; Extend # Mn TAKRI SIGN NUKTA +1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +11720..11721 ; Extend # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA +11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU +11726 ; Extend # Mc AHOM VOWEL SIGN E +11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER +1182C..1182E ; Extend # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II +1182F..11837 ; Extend # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA +11838 ; Extend # Mc DOGRA SIGN VISARGA +11839..1183A ; Extend # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA +11930..11935 ; Extend # Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E +11937..11938 ; Extend # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O +1193B..1193C ; Extend # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU +1193D ; Extend # Mc DIVES AKURU SIGN HALANTA +1193E ; Extend # Mn DIVES AKURU VIRAMA +11940 ; Extend # Mc DIVES AKURU MEDIAL YA +11942 ; Extend # Mc DIVES AKURU MEDIAL RA +11943 ; Extend # Mn DIVES AKURU SIGN NUKTA +119D1..119D3 ; Extend # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II +119D4..119D7 ; Extend # Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR +119DA..119DB ; Extend # Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI +119DC..119DF ; Extend # Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA +119E0 ; Extend # Mn NANDINAGARI SIGN VIRAMA +119E4 ; Extend # Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E +11A01..11A0A ; Extend # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A33..11A38 ; Extend # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A39 ; Extend # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3B..11A3E ; Extend # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A47 ; Extend # Mn ZANABAZAR SQUARE SUBJOINER +11A51..11A56 ; Extend # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58 ; Extend # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B ; Extend # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A8A..11A96 ; Extend # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97 ; Extend # Mc SOYOMBO SIGN VISARGA +11A98..11A99 ; Extend # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11C2F ; Extend # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36 ; Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D ; Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E ; Extend # Mc BHAIKSUKI SIGN VISARGA +11C3F ; Extend # Mn BHAIKSUKI SIGN VIRAMA +11C92..11CA7 ; Extend # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9 ; Extend # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0 ; Extend # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1 ; Extend # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3 ; Extend # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4 ; Extend # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6 ; Extend # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D31..11D36 ; Extend # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; Extend # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; Extend # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45 ; Extend # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D47 ; Extend # Mn MASARAM GONDI RA-KARA +11D8A..11D8E ; Extend # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU +11D90..11D91 ; Extend # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI +11D93..11D94 ; Extend # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU +11D95 ; Extend # Mn GUNJALA GONDI SIGN ANUSVARA +11D96 ; Extend # Mc GUNJALA GONDI SIGN VISARGA +11D97 ; Extend # Mn GUNJALA GONDI VIRAMA +11EF3..11EF4 ; Extend # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U +11EF5..11EF6 ; Extend # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O +16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE +16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM +16F4F ; Extend # Mn MIAO SIGN CONSONANT MODIFIER BAR +16F51..16F87 ; Extend # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI +16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW +16FE4 ; Extend # Mn KHITAN SMALL SCRIPT FILLER +16FF0..16FF1 ; Extend # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY +1BC9D..1BC9E ; Extend # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1D165..1D166 ; Extend # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM +1D167..1D169 ; Extend # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 +1D16D..1D172 ; Extend # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 +1D17B..1D182 ; Extend # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE +1D185..1D18B ; Extend # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE +1D1AA..1D1AD ; Extend # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1D242..1D244 ; Extend # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME +1DA00..1DA36 ; Extend # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN +1DA3B..1DA6C ; Extend # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT +1DA75 ; Extend # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS +1DA84 ; Extend # Mn SIGNWRITING LOCATION HEAD NECK +1DA9B..1DA9F ; Extend # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 +1DAA1..1DAAF ; Extend # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; Extend # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; Extend # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E130..1E136 ; Extend # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D +1E2EC..1E2EF ; Extend # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI +1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 +E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG +E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 + +# Total code points: 2399 + +# ================================================ + +1F1E6..1F1FF ; Regional_Indicator # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z + +# Total code points: 26 + +# ================================================ + +00AD ; Format # Cf SOFT HYPHEN +0600..0605 ; Format # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE +061C ; Format # Cf ARABIC LETTER MARK +06DD ; Format # Cf ARABIC END OF AYAH +070F ; Format # Cf SYRIAC ABBREVIATION MARK +08E2 ; Format # Cf ARABIC DISPUTED END OF AYAH +180E ; Format # Cf MONGOLIAN VOWEL SEPARATOR +200E..200F ; Format # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK +202A..202E ; Format # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE +2060..2064 ; Format # Cf [5] WORD JOINER..INVISIBLE PLUS +2066..206F ; Format # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES +FEFF ; Format # Cf ZERO WIDTH NO-BREAK SPACE +FFF9..FFFB ; Format # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR +110BD ; Format # Cf KAITHI NUMBER SIGN +110CD ; Format # Cf KAITHI NUMBER SIGN ABOVE +13430..13438 ; Format # Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT +1BCA0..1BCA3 ; Format # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP +1D173..1D17A ; Format # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE +E0001 ; Format # Cf LANGUAGE TAG + +# Total code points: 62 + +# ================================================ + +3031..3035 ; Katakana # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF +309B..309C ; Katakana # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +30A0 ; Katakana # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN +30A1..30FA ; Katakana # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO +30FC..30FE ; Katakana # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK +30FF ; Katakana # Lo KATAKANA DIGRAPH KOTO +31F0..31FF ; Katakana # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO +32D0..32FE ; Katakana # So [47] CIRCLED KATAKANA A..CIRCLED KATAKANA WO +3300..3357 ; Katakana # So [88] SQUARE APAATO..SQUARE WATTO +FF66..FF6F ; Katakana # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU +FF70 ; Katakana # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N +1B000 ; Katakana # Lo KATAKANA LETTER ARCHAIC E +1B164..1B167 ; Katakana # Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N + +# Total code points: 314 + +# ================================================ + +0041..005A ; ALetter # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z +0061..007A ; ALetter # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z +00AA ; ALetter # Lo FEMININE ORDINAL INDICATOR +00B5 ; ALetter # L& MICRO SIGN +00BA ; ALetter # Lo MASCULINE ORDINAL INDICATOR +00C0..00D6 ; ALetter # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS +00D8..00F6 ; ALetter # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS +00F8..01BA ; ALetter # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL +01BB ; ALetter # Lo LATIN LETTER TWO WITH STROKE +01BC..01BF ; ALetter # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN +01C0..01C3 ; ALetter # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK +01C4..0293 ; ALetter # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL +0294 ; ALetter # Lo LATIN LETTER GLOTTAL STOP +0295..02AF ; ALetter # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +02B0..02C1 ; ALetter # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP +02C2..02C5 ; ALetter # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD +02C6..02D1 ; ALetter # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON +02D2..02D7 ; ALetter # Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN +02DE..02DF ; ALetter # Sk [2] MODIFIER LETTER RHOTIC HOOK..MODIFIER LETTER CROSS ACCENT +02E0..02E4 ; ALetter # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +02E5..02EB ; ALetter # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK +02EC ; ALetter # Lm MODIFIER LETTER VOICING +02ED ; ALetter # Sk MODIFIER LETTER UNASPIRATED +02EE ; ALetter # Lm MODIFIER LETTER DOUBLE APOSTROPHE +02EF..02FF ; ALetter # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW +0370..0373 ; ALetter # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI +0374 ; ALetter # Lm GREEK NUMERAL SIGN +0376..0377 ; ALetter # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA +037A ; ALetter # Lm GREEK YPOGEGRAMMENI +037B..037D ; ALetter # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL +037F ; ALetter # L& GREEK CAPITAL LETTER YOT +0386 ; ALetter # L& GREEK CAPITAL LETTER ALPHA WITH TONOS +0388..038A ; ALetter # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS +038C ; ALetter # L& GREEK CAPITAL LETTER OMICRON WITH TONOS +038E..03A1 ; ALetter # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO +03A3..03F5 ; ALetter # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL +03F7..0481 ; ALetter # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA +048A..052F ; ALetter # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER +0531..0556 ; ALetter # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH +0559 ; ALetter # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING +055A..055C ; ALetter # Po [3] ARMENIAN APOSTROPHE..ARMENIAN EXCLAMATION MARK +055E ; ALetter # Po ARMENIAN QUESTION MARK +0560..0588 ; ALetter # L& [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE +058A ; ALetter # Pd ARMENIAN HYPHEN +05F3 ; ALetter # Po HEBREW PUNCTUATION GERESH +0620..063F ; ALetter # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE +0640 ; ALetter # Lm ARABIC TATWEEL +0641..064A ; ALetter # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH +066E..066F ; ALetter # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF +0671..06D3 ; ALetter # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +06D5 ; ALetter # Lo ARABIC LETTER AE +06E5..06E6 ; ALetter # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH +06EE..06EF ; ALetter # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V +06FA..06FC ; ALetter # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW +06FF ; ALetter # Lo ARABIC LETTER HEH WITH INVERTED V +0710 ; ALetter # Lo SYRIAC LETTER ALAPH +0712..072F ; ALetter # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH +074D..07A5 ; ALetter # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU +07B1 ; ALetter # Lo THAANA LETTER NAA +07CA..07EA ; ALetter # Lo [33] NKO LETTER A..NKO LETTER JONA RA +07F4..07F5 ; ALetter # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE +07FA ; ALetter # Lm NKO LAJANYALAN +0800..0815 ; ALetter # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF +081A ; ALetter # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT +0824 ; ALetter # Lm SAMARITAN MODIFIER LETTER SHORT A +0828 ; ALetter # Lm SAMARITAN MODIFIER LETTER I +0840..0858 ; ALetter # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN +0860..086A ; ALetter # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA +08A0..08B4 ; ALetter # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B6..08C7 ; ALetter # Lo [18] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE +0904..0939 ; ALetter # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA +093D ; ALetter # Lo DEVANAGARI SIGN AVAGRAHA +0950 ; ALetter # Lo DEVANAGARI OM +0958..0961 ; ALetter # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL +0971 ; ALetter # Lm DEVANAGARI SIGN HIGH SPACING DOT +0972..0980 ; ALetter # Lo [15] DEVANAGARI LETTER CANDRA A..BENGALI ANJI +0985..098C ; ALetter # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L +098F..0990 ; ALetter # Lo [2] BENGALI LETTER E..BENGALI LETTER AI +0993..09A8 ; ALetter # Lo [22] BENGALI LETTER O..BENGALI LETTER NA +09AA..09B0 ; ALetter # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA +09B2 ; ALetter # Lo BENGALI LETTER LA +09B6..09B9 ; ALetter # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA +09BD ; ALetter # Lo BENGALI SIGN AVAGRAHA +09CE ; ALetter # Lo BENGALI LETTER KHANDA TA +09DC..09DD ; ALetter # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA +09DF..09E1 ; ALetter # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL +09F0..09F1 ; ALetter # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL +09FC ; ALetter # Lo BENGALI LETTER VEDIC ANUSVARA +0A05..0A0A ; ALetter # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU +0A0F..0A10 ; ALetter # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI +0A13..0A28 ; ALetter # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA +0A2A..0A30 ; ALetter # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA +0A32..0A33 ; ALetter # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA +0A35..0A36 ; ALetter # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA +0A38..0A39 ; ALetter # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA +0A59..0A5C ; ALetter # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA +0A5E ; ALetter # Lo GURMUKHI LETTER FA +0A72..0A74 ; ALetter # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR +0A85..0A8D ; ALetter # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E +0A8F..0A91 ; ALetter # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O +0A93..0AA8 ; ALetter # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA +0AAA..0AB0 ; ALetter # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA +0AB2..0AB3 ; ALetter # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA +0AB5..0AB9 ; ALetter # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA +0ABD ; ALetter # Lo GUJARATI SIGN AVAGRAHA +0AD0 ; ALetter # Lo GUJARATI OM +0AE0..0AE1 ; ALetter # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL +0AF9 ; ALetter # Lo GUJARATI LETTER ZHA +0B05..0B0C ; ALetter # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L +0B0F..0B10 ; ALetter # Lo [2] ORIYA LETTER E..ORIYA LETTER AI +0B13..0B28 ; ALetter # Lo [22] ORIYA LETTER O..ORIYA LETTER NA +0B2A..0B30 ; ALetter # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA +0B32..0B33 ; ALetter # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA +0B35..0B39 ; ALetter # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA +0B3D ; ALetter # Lo ORIYA SIGN AVAGRAHA +0B5C..0B5D ; ALetter # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA +0B5F..0B61 ; ALetter # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL +0B71 ; ALetter # Lo ORIYA LETTER WA +0B83 ; ALetter # Lo TAMIL SIGN VISARGA +0B85..0B8A ; ALetter # Lo [6] TAMIL LETTER A..TAMIL LETTER UU +0B8E..0B90 ; ALetter # Lo [3] TAMIL LETTER E..TAMIL LETTER AI +0B92..0B95 ; ALetter # Lo [4] TAMIL LETTER O..TAMIL LETTER KA +0B99..0B9A ; ALetter # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA +0B9C ; ALetter # Lo TAMIL LETTER JA +0B9E..0B9F ; ALetter # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA +0BA3..0BA4 ; ALetter # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA +0BA8..0BAA ; ALetter # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA +0BAE..0BB9 ; ALetter # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA +0BD0 ; ALetter # Lo TAMIL OM +0C05..0C0C ; ALetter # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L +0C0E..0C10 ; ALetter # Lo [3] TELUGU LETTER E..TELUGU LETTER AI +0C12..0C28 ; ALetter # Lo [23] TELUGU LETTER O..TELUGU LETTER NA +0C2A..0C39 ; ALetter # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA +0C3D ; ALetter # Lo TELUGU SIGN AVAGRAHA +0C58..0C5A ; ALetter # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA +0C60..0C61 ; ALetter # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL +0C80 ; ALetter # Lo KANNADA SIGN SPACING CANDRABINDU +0C85..0C8C ; ALetter # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L +0C8E..0C90 ; ALetter # Lo [3] KANNADA LETTER E..KANNADA LETTER AI +0C92..0CA8 ; ALetter # Lo [23] KANNADA LETTER O..KANNADA LETTER NA +0CAA..0CB3 ; ALetter # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA +0CB5..0CB9 ; ALetter # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA +0CBD ; ALetter # Lo KANNADA SIGN AVAGRAHA +0CDE ; ALetter # Lo KANNADA LETTER FA +0CE0..0CE1 ; ALetter # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL +0CF1..0CF2 ; ALetter # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA +0D04..0D0C ; ALetter # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L +0D0E..0D10 ; ALetter # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI +0D12..0D3A ; ALetter # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA +0D3D ; ALetter # Lo MALAYALAM SIGN AVAGRAHA +0D4E ; ALetter # Lo MALAYALAM LETTER DOT REPH +0D54..0D56 ; ALetter # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL +0D5F..0D61 ; ALetter # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL +0D7A..0D7F ; ALetter # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K +0D85..0D96 ; ALetter # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA +0D9A..0DB1 ; ALetter # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA +0DB3..0DBB ; ALetter # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA +0DBD ; ALetter # Lo SINHALA LETTER DANTAJA LAYANNA +0DC0..0DC6 ; ALetter # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA +0F00 ; ALetter # Lo TIBETAN SYLLABLE OM +0F40..0F47 ; ALetter # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA +0F49..0F6C ; ALetter # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA +0F88..0F8C ; ALetter # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN +10A0..10C5 ; ALetter # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE +10C7 ; ALetter # L& GEORGIAN CAPITAL LETTER YN +10CD ; ALetter # L& GEORGIAN CAPITAL LETTER AEN +10D0..10FA ; ALetter # L& [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN +10FC ; ALetter # Lm MODIFIER LETTER GEORGIAN NAR +10FD..10FF ; ALetter # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN +1100..1248 ; ALetter # Lo [329] HANGUL CHOSEONG KIYEOK..ETHIOPIC SYLLABLE QWA +124A..124D ; ALetter # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE +1250..1256 ; ALetter # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO +1258 ; ALetter # Lo ETHIOPIC SYLLABLE QHWA +125A..125D ; ALetter # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE +1260..1288 ; ALetter # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA +128A..128D ; ALetter # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE +1290..12B0 ; ALetter # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA +12B2..12B5 ; ALetter # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE +12B8..12BE ; ALetter # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO +12C0 ; ALetter # Lo ETHIOPIC SYLLABLE KXWA +12C2..12C5 ; ALetter # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE +12C8..12D6 ; ALetter # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O +12D8..1310 ; ALetter # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA +1312..1315 ; ALetter # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE +1318..135A ; ALetter # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA +1380..138F ; ALetter # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE +13A0..13F5 ; ALetter # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +13F8..13FD ; ALetter # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV +1401..166C ; ALetter # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA +166F..167F ; ALetter # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W +1681..169A ; ALetter # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH +16A0..16EA ; ALetter # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X +16EE..16F0 ; ALetter # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL +16F1..16F8 ; ALetter # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC +1700..170C ; ALetter # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA +170E..1711 ; ALetter # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA +1720..1731 ; ALetter # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA +1740..1751 ; ALetter # Lo [18] BUHID LETTER A..BUHID LETTER HA +1760..176C ; ALetter # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA +176E..1770 ; ALetter # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA +1820..1842 ; ALetter # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI +1843 ; ALetter # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN +1844..1878 ; ALetter # Lo [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS +1880..1884 ; ALetter # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1887..18A8 ; ALetter # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA +18AA ; ALetter # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA +18B0..18F5 ; ALetter # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S +1900..191E ; ALetter # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA +1A00..1A16 ; ALetter # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA +1B05..1B33 ; ALetter # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA +1B45..1B4B ; ALetter # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK +1B83..1BA0 ; ALetter # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA +1BAE..1BAF ; ALetter # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA +1BBA..1BE5 ; ALetter # Lo [44] SUNDANESE AVAGRAHA..BATAK LETTER U +1C00..1C23 ; ALetter # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A +1C4D..1C4F ; ALetter # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA +1C5A..1C77 ; ALetter # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH +1C78..1C7D ; ALetter # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD +1C80..1C88 ; ALetter # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C90..1CBA ; ALetter # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN +1CBD..1CBF ; ALetter # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN +1CE9..1CEC ; ALetter # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL +1CEE..1CF3 ; ALetter # Lo [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA +1CF5..1CF6 ; ALetter # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA +1CFA ; ALetter # Lo VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA +1D00..1D2B ; ALetter # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL +1D2C..1D6A ; ALetter # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI +1D6B..1D77 ; ALetter # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G +1D78 ; ALetter # Lm MODIFIER LETTER CYRILLIC EN +1D79..1D9A ; ALetter # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK +1D9B..1DBF ; ALetter # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA +1E00..1F15 ; ALetter # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F18..1F1D ; ALetter # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F20..1F45 ; ALetter # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F48..1F4D ; ALetter # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50..1F57 ; ALetter # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F59 ; ALetter # L& GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B ; ALetter # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D ; ALetter # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F..1F7D ; ALetter # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA +1F80..1FB4 ; ALetter # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6..1FBC ; ALetter # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBE ; ALetter # L& GREEK PROSGEGRAMMENI +1FC2..1FC4 ; ALetter # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6..1FCC ; ALetter # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FD0..1FD3 ; ALetter # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6..1FDB ; ALetter # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA +1FE0..1FEC ; ALetter # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA +1FF2..1FF4 ; ALetter # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6..1FFC ; ALetter # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +2071 ; ALetter # Lm SUPERSCRIPT LATIN SMALL LETTER I +207F ; ALetter # Lm SUPERSCRIPT LATIN SMALL LETTER N +2090..209C ; ALetter # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T +2102 ; ALetter # L& DOUBLE-STRUCK CAPITAL C +2107 ; ALetter # L& EULER CONSTANT +210A..2113 ; ALetter # L& [10] SCRIPT SMALL G..SCRIPT SMALL L +2115 ; ALetter # L& DOUBLE-STRUCK CAPITAL N +2119..211D ; ALetter # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R +2124 ; ALetter # L& DOUBLE-STRUCK CAPITAL Z +2126 ; ALetter # L& OHM SIGN +2128 ; ALetter # L& BLACK-LETTER CAPITAL Z +212A..212D ; ALetter # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C +212F..2134 ; ALetter # L& [6] SCRIPT SMALL E..SCRIPT SMALL O +2135..2138 ; ALetter # Lo [4] ALEF SYMBOL..DALET SYMBOL +2139 ; ALetter # L& INFORMATION SOURCE +213C..213F ; ALetter # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI +2145..2149 ; ALetter # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J +214E ; ALetter # L& TURNED SMALL F +2160..2182 ; ALetter # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND +2183..2184 ; ALetter # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C +2185..2188 ; ALetter # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND +24B6..24E9 ; ALetter # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z +2C00..2C2E ; ALetter # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +2C30..2C5E ; ALetter # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE +2C60..2C7B ; ALetter # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E +2C7C..2C7D ; ALetter # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V +2C7E..2CE4 ; ALetter # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI +2CEB..2CEE ; ALetter # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA +2CF2..2CF3 ; ALetter # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI +2D00..2D25 ; ALetter # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE +2D27 ; ALetter # L& GEORGIAN SMALL LETTER YN +2D2D ; ALetter # L& GEORGIAN SMALL LETTER AEN +2D30..2D67 ; ALetter # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO +2D6F ; ALetter # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK +2D80..2D96 ; ALetter # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE +2DA0..2DA6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO +2DA8..2DAE ; ALetter # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO +2DB0..2DB6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO +2DB8..2DBE ; ALetter # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO +2DC0..2DC6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO +2DC8..2DCE ; ALetter # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO +2DD0..2DD6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO +2DD8..2DDE ; ALetter # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO +2E2F ; ALetter # Lm VERTICAL TILDE +3005 ; ALetter # Lm IDEOGRAPHIC ITERATION MARK +303B ; ALetter # Lm VERTICAL IDEOGRAPHIC ITERATION MARK +303C ; ALetter # Lo MASU MARK +3105..312F ; ALetter # Lo [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN +3131..318E ; ALetter # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE +31A0..31BF ; ALetter # Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH +A000..A014 ; ALetter # Lo [21] YI SYLLABLE IT..YI SYLLABLE E +A015 ; ALetter # Lm YI SYLLABLE WU +A016..A48C ; ALetter # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR +A4D0..A4F7 ; ALetter # Lo [40] LISU LETTER BA..LISU LETTER OE +A4F8..A4FD ; ALetter # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU +A500..A60B ; ALetter # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG +A60C ; ALetter # Lm VAI SYLLABLE LENGTHENER +A610..A61F ; ALetter # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG +A62A..A62B ; ALetter # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO +A640..A66D ; ALetter # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O +A66E ; ALetter # Lo CYRILLIC LETTER MULTIOCULAR O +A67F ; ALetter # Lm CYRILLIC PAYEROK +A680..A69B ; ALetter # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O +A69C..A69D ; ALetter # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN +A6A0..A6E5 ; ALetter # Lo [70] BAMUM LETTER A..BAMUM LETTER KI +A6E6..A6EF ; ALetter # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM +A708..A716 ; ALetter # Sk [15] MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR +A717..A71F ; ALetter # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK +A720..A721 ; ALetter # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE +A722..A76F ; ALetter # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON +A770 ; ALetter # Lm MODIFIER LETTER US +A771..A787 ; ALetter # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T +A788 ; ALetter # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT +A789..A78A ; ALetter # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN +A78B..A78E ; ALetter # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT +A78F ; ALetter # Lo LATIN LETTER SINOLOGICAL DOT +A790..A7BF ; ALetter # L& [48] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER GLOTTAL U +A7C2..A7CA ; ALetter # L& [9] LATIN CAPITAL LETTER ANGLICANA W..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7F5..A7F6 ; ALetter # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H +A7F7 ; ALetter # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I +A7F8..A7F9 ; ALetter # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE +A7FA ; ALetter # L& LATIN LETTER SMALL CAPITAL TURNED M +A7FB..A801 ; ALetter # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I +A803..A805 ; ALetter # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O +A807..A80A ; ALetter # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO +A80C..A822 ; ALetter # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO +A840..A873 ; ALetter # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU +A882..A8B3 ; ALetter # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA +A8F2..A8F7 ; ALetter # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA +A8FB ; ALetter # Lo DEVANAGARI HEADSTROKE +A8FD..A8FE ; ALetter # Lo [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY +A90A..A925 ; ALetter # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO +A930..A946 ; ALetter # Lo [23] REJANG LETTER KA..REJANG LETTER A +A960..A97C ; ALetter # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH +A984..A9B2 ; ALetter # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA +A9CF ; ALetter # Lm JAVANESE PANGRANGKEP +AA00..AA28 ; ALetter # Lo [41] CHAM LETTER A..CHAM LETTER HA +AA40..AA42 ; ALetter # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG +AA44..AA4B ; ALetter # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS +AAE0..AAEA ; ALetter # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA +AAF2 ; ALetter # Lo MEETEI MAYEK ANJI +AAF3..AAF4 ; ALetter # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK +AB01..AB06 ; ALetter # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO +AB09..AB0E ; ALetter # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO +AB11..AB16 ; ALetter # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO +AB20..AB26 ; ALetter # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO +AB28..AB2E ; ALetter # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO +AB30..AB5A ; ALetter # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG +AB5B ; ALetter # Sk MODIFIER BREVE WITH INVERTED BREVE +AB5C..AB5F ; ALetter # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK +AB60..AB68 ; ALetter # L& [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE +AB69 ; ALetter # Lm MODIFIER LETTER SMALL TURNED W +AB70..ABBF ; ALetter # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA +ABC0..ABE2 ; ALetter # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM +AC00..D7A3 ; ALetter # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH +D7B0..D7C6 ; ALetter # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E +D7CB..D7FB ; ALetter # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH +FB00..FB06 ; ALetter # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST +FB13..FB17 ; ALetter # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH +FB50..FBB1 ; ALetter # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM +FBD3..FD3D ; ALetter # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM +FD50..FD8F ; ALetter # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FD92..FDC7 ; ALetter # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM +FDF0..FDFB ; ALetter # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU +FE70..FE74 ; ALetter # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM +FE76..FEFC ; ALetter # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM +FF21..FF3A ; ALetter # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z +FF41..FF5A ; ALetter # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z +FFA0..FFBE ; ALetter # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH +FFC2..FFC7 ; ALetter # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E +FFCA..FFCF ; ALetter # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE +FFD2..FFD7 ; ALetter # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU +FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I +10000..1000B ; ALetter # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE +1000D..10026 ; ALetter # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO +10028..1003A ; ALetter # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO +1003C..1003D ; ALetter # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE +1003F..1004D ; ALetter # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO +10050..1005D ; ALetter # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089 +10080..100FA ; ALetter # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305 +10140..10174 ; ALetter # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS +10280..1029C ; ALetter # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X +102A0..102D0 ; ALetter # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3 +10300..1031F ; ALetter # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS +1032D..10340 ; ALetter # Lo [20] OLD ITALIC LETTER YE..GOTHIC LETTER PAIRTHRA +10341 ; ALetter # Nl GOTHIC LETTER NINETY +10342..10349 ; ALetter # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL +1034A ; ALetter # Nl GOTHIC LETTER NINE HUNDRED +10350..10375 ; ALetter # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA +10380..1039D ; ALetter # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU +103A0..103C3 ; ALetter # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA +103C8..103CF ; ALetter # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH +103D1..103D5 ; ALetter # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED +10400..1044F ; ALetter # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW +10450..1049D ; ALetter # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO +104B0..104D3 ; ALetter # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB ; ALetter # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA +10500..10527 ; ALetter # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE +10530..10563 ; ALetter # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW +10600..10736 ; ALetter # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 +10740..10755 ; ALetter # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE +10760..10767 ; ALetter # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 +10800..10805 ; ALetter # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA +10808 ; ALetter # Lo CYPRIOT SYLLABLE JO +1080A..10835 ; ALetter # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO +10837..10838 ; ALetter # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE +1083C ; ALetter # Lo CYPRIOT SYLLABLE ZA +1083F..10855 ; ALetter # Lo [23] CYPRIOT SYLLABLE ZO..IMPERIAL ARAMAIC LETTER TAW +10860..10876 ; ALetter # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW +10880..1089E ; ALetter # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW +108E0..108F2 ; ALetter # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH +108F4..108F5 ; ALetter # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW +10900..10915 ; ALetter # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU +10920..10939 ; ALetter # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C +10980..109B7 ; ALetter # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA +109BE..109BF ; ALetter # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN +10A00 ; ALetter # Lo KHAROSHTHI LETTER A +10A10..10A13 ; ALetter # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA +10A15..10A17 ; ALetter # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA +10A19..10A35 ; ALetter # Lo [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA +10A60..10A7C ; ALetter # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH +10A80..10A9C ; ALetter # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH +10AC0..10AC7 ; ALetter # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW +10AC9..10AE4 ; ALetter # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW +10B00..10B35 ; ALetter # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE +10B40..10B55 ; ALetter # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW +10B60..10B72 ; ALetter # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW +10B80..10B91 ; ALetter # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW +10C00..10C48 ; ALetter # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH +10C80..10CB2 ; ALetter # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10CC0..10CF2 ; ALetter # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10D00..10D23 ; ALetter # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10E80..10EA9 ; ALetter # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET +10EB0..10EB1 ; ALetter # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10F00..10F1C ; ALetter # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL +10F27 ; ALetter # Lo OLD SOGDIAN LIGATURE AYIN-DALETH +10F30..10F45 ; ALetter # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN +10FB0..10FC4 ; ALetter # Lo [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW +10FE0..10FF6 ; ALetter # Lo [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH +11003..11037 ; ALetter # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA +11083..110AF ; ALetter # Lo [45] KAITHI LETTER A..KAITHI LETTER HA +110D0..110E8 ; ALetter # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE +11103..11126 ; ALetter # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA +11144 ; ALetter # Lo CHAKMA LETTER LHAA +11147 ; ALetter # Lo CHAKMA LETTER VAA +11150..11172 ; ALetter # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA +11176 ; ALetter # Lo MAHAJANI LIGATURE SHRI +11183..111B2 ; ALetter # Lo [48] SHARADA LETTER A..SHARADA LETTER HA +111C1..111C4 ; ALetter # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM +111DA ; ALetter # Lo SHARADA EKAM +111DC ; ALetter # Lo SHARADA HEADSTROKE +11200..11211 ; ALetter # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA +11213..1122B ; ALetter # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA +11280..11286 ; ALetter # Lo [7] MULTANI LETTER A..MULTANI LETTER GA +11288 ; ALetter # Lo MULTANI LETTER GHA +1128A..1128D ; ALetter # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA +1128F..1129D ; ALetter # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA +1129F..112A8 ; ALetter # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA +112B0..112DE ; ALetter # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA +11305..1130C ; ALetter # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L +1130F..11310 ; ALetter # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI +11313..11328 ; ALetter # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA +1132A..11330 ; ALetter # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA +11332..11333 ; ALetter # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA +11335..11339 ; ALetter # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA +1133D ; ALetter # Lo GRANTHA SIGN AVAGRAHA +11350 ; ALetter # Lo GRANTHA OM +1135D..11361 ; ALetter # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11400..11434 ; ALetter # Lo [53] NEWA LETTER A..NEWA LETTER HA +11447..1144A ; ALetter # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI +1145F..11461 ; ALetter # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA +11480..114AF ; ALetter # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA +114C4..114C5 ; ALetter # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG +114C7 ; ALetter # Lo TIRHUTA OM +11580..115AE ; ALetter # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA +115D8..115DB ; ALetter # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U +11600..1162F ; ALetter # Lo [48] MODI LETTER A..MODI LETTER LLA +11644 ; ALetter # Lo MODI SIGN HUVA +11680..116AA ; ALetter # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA +116B8 ; ALetter # Lo TAKRI LETTER ARCHAIC KHA +11800..1182B ; ALetter # Lo [44] DOGRA LETTER A..DOGRA LETTER RRA +118A0..118DF ; ALetter # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO +118FF..11906 ; ALetter # Lo [8] WARANG CITI OM..DIVES AKURU LETTER E +11909 ; ALetter # Lo DIVES AKURU LETTER O +1190C..11913 ; ALetter # Lo [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA +11915..11916 ; ALetter # Lo [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA +11918..1192F ; ALetter # Lo [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA +1193F ; ALetter # Lo DIVES AKURU PREFIXED NASAL SIGN +11941 ; ALetter # Lo DIVES AKURU INITIAL RA +119A0..119A7 ; ALetter # Lo [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR +119AA..119D0 ; ALetter # Lo [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA +119E1 ; ALetter # Lo NANDINAGARI SIGN AVAGRAHA +119E3 ; ALetter # Lo NANDINAGARI HEADSTROKE +11A00 ; ALetter # Lo ZANABAZAR SQUARE LETTER A +11A0B..11A32 ; ALetter # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A3A ; ALetter # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A50 ; ALetter # Lo SOYOMBO LETTER A +11A5C..11A89 ; ALetter # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA +11A9D ; ALetter # Lo SOYOMBO MARK PLUTA +11AC0..11AF8 ; ALetter # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11C00..11C08 ; ALetter # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E ; ALetter # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C40 ; ALetter # Lo BHAIKSUKI SIGN AVAGRAHA +11C72..11C8F ; ALetter # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11D00..11D06 ; ALetter # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09 ; ALetter # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30 ; ALetter # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D46 ; ALetter # Lo MASARAM GONDI REPHA +11D60..11D65 ; ALetter # Lo [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU +11D67..11D68 ; ALetter # Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI +11D6A..11D89 ; ALetter # Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA +11D98 ; ALetter # Lo GUNJALA GONDI OM +11EE0..11EF2 ; ALetter # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA +11FB0 ; ALetter # Lo LISU LETTER YHA +12000..12399 ; ALetter # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U +12400..1246E ; ALetter # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM +12480..12543 ; ALetter # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU +13000..1342E ; ALetter # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032 +14400..14646 ; ALetter # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16800..16A38 ; ALetter # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ +16A40..16A5E ; ALetter # Lo [31] MRO LETTER TA..MRO LETTER TEK +16AD0..16AED ; ALetter # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I +16B00..16B2F ; ALetter # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU +16B40..16B43 ; ALetter # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16B63..16B77 ; ALetter # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS +16B7D..16B8F ; ALetter # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16E40..16E7F ; ALetter # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16F00..16F4A ; ALetter # Lo [75] MIAO LETTER PA..MIAO LETTER RTE +16F50 ; ALetter # Lo MIAO LETTER NASALIZATION +16F93..16F9F ; ALetter # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 +16FE0..16FE1 ; ALetter # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +16FE3 ; ALetter # Lm OLD CHINESE ITERATION MARK +1BC00..1BC6A ; ALetter # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M +1BC70..1BC7C ; ALetter # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK +1BC80..1BC88 ; ALetter # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL +1BC90..1BC99 ; ALetter # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW +1D400..1D454 ; ALetter # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G +1D456..1D49C ; ALetter # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A +1D49E..1D49F ; ALetter # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D +1D4A2 ; ALetter # L& MATHEMATICAL SCRIPT CAPITAL G +1D4A5..1D4A6 ; ALetter # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K +1D4A9..1D4AC ; ALetter # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q +1D4AE..1D4B9 ; ALetter # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D +1D4BB ; ALetter # L& MATHEMATICAL SCRIPT SMALL F +1D4BD..1D4C3 ; ALetter # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N +1D4C5..1D505 ; ALetter # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B +1D507..1D50A ; ALetter # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G +1D50D..1D514 ; ALetter # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q +1D516..1D51C ; ALetter # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y +1D51E..1D539 ; ALetter # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D53B..1D53E ; ALetter # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D540..1D544 ; ALetter # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D546 ; ALetter # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D54A..1D550 ; ALetter # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D552..1D6A5 ; ALetter # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J +1D6A8..1D6C0 ; ALetter # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA +1D6C2..1D6DA ; ALetter # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA +1D6DC..1D6FA ; ALetter # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA +1D6FC..1D714 ; ALetter # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA +1D716..1D734 ; ALetter # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D736..1D74E ; ALetter # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D750..1D76E ; ALetter # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D770..1D788 ; ALetter # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D78A..1D7A8 ; ALetter # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1D7AA..1D7C2 ; ALetter # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +1D7C4..1D7CB ; ALetter # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA +1E100..1E12C ; ALetter # Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W +1E137..1E13D ; ALetter # Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER +1E14E ; ALetter # Lo NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ +1E2C0..1E2EB ; ALetter # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH +1E800..1E8C4 ; ALetter # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON +1E900..1E943 ; ALetter # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA +1E94B ; ALetter # Lm ADLAM NASALIZATION MARK +1EE00..1EE03 ; ALetter # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL +1EE05..1EE1F ; ALetter # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF +1EE21..1EE22 ; ALetter # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM +1EE24 ; ALetter # Lo ARABIC MATHEMATICAL INITIAL HEH +1EE27 ; ALetter # Lo ARABIC MATHEMATICAL INITIAL HAH +1EE29..1EE32 ; ALetter # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF +1EE34..1EE37 ; ALetter # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH +1EE39 ; ALetter # Lo ARABIC MATHEMATICAL INITIAL DAD +1EE3B ; ALetter # Lo ARABIC MATHEMATICAL INITIAL GHAIN +1EE42 ; ALetter # Lo ARABIC MATHEMATICAL TAILED JEEM +1EE47 ; ALetter # Lo ARABIC MATHEMATICAL TAILED HAH +1EE49 ; ALetter # Lo ARABIC MATHEMATICAL TAILED YEH +1EE4B ; ALetter # Lo ARABIC MATHEMATICAL TAILED LAM +1EE4D..1EE4F ; ALetter # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN +1EE51..1EE52 ; ALetter # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF +1EE54 ; ALetter # Lo ARABIC MATHEMATICAL TAILED SHEEN +1EE57 ; ALetter # Lo ARABIC MATHEMATICAL TAILED KHAH +1EE59 ; ALetter # Lo ARABIC MATHEMATICAL TAILED DAD +1EE5B ; ALetter # Lo ARABIC MATHEMATICAL TAILED GHAIN +1EE5D ; ALetter # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON +1EE5F ; ALetter # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF +1EE61..1EE62 ; ALetter # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM +1EE64 ; ALetter # Lo ARABIC MATHEMATICAL STRETCHED HEH +1EE67..1EE6A ; ALetter # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF +1EE6C..1EE72 ; ALetter # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF +1EE74..1EE77 ; ALetter # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH +1EE79..1EE7C ; ALetter # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH +1EE7E ; ALetter # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH +1EE80..1EE89 ; ALetter # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH +1EE8B..1EE9B ; ALetter # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN +1EEA1..1EEA3 ; ALetter # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL +1EEA5..1EEA9 ; ALetter # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH +1EEAB..1EEBB ; ALetter # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN +1F130..1F149 ; ALetter # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z +1F150..1F169 ; ALetter # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F170..1F189 ; ALetter # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z + +# Total code points: 28854 + +# ================================================ + +003A ; MidLetter # Po COLON +00B7 ; MidLetter # Po MIDDLE DOT +0387 ; MidLetter # Po GREEK ANO TELEIA +055F ; MidLetter # Po ARMENIAN ABBREVIATION MARK +05F4 ; MidLetter # Po HEBREW PUNCTUATION GERSHAYIM +2027 ; MidLetter # Po HYPHENATION POINT +FE13 ; MidLetter # Po PRESENTATION FORM FOR VERTICAL COLON +FE55 ; MidLetter # Po SMALL COLON +FF1A ; MidLetter # Po FULLWIDTH COLON + +# Total code points: 9 + +# ================================================ + +002C ; MidNum # Po COMMA +003B ; MidNum # Po SEMICOLON +037E ; MidNum # Po GREEK QUESTION MARK +0589 ; MidNum # Po ARMENIAN FULL STOP +060C..060D ; MidNum # Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR +066C ; MidNum # Po ARABIC THOUSANDS SEPARATOR +07F8 ; MidNum # Po NKO COMMA +2044 ; MidNum # Sm FRACTION SLASH +FE10 ; MidNum # Po PRESENTATION FORM FOR VERTICAL COMMA +FE14 ; MidNum # Po PRESENTATION FORM FOR VERTICAL SEMICOLON +FE50 ; MidNum # Po SMALL COMMA +FE54 ; MidNum # Po SMALL SEMICOLON +FF0C ; MidNum # Po FULLWIDTH COMMA +FF1B ; MidNum # Po FULLWIDTH SEMICOLON + +# Total code points: 15 + +# ================================================ + +002E ; MidNumLet # Po FULL STOP +2018 ; MidNumLet # Pi LEFT SINGLE QUOTATION MARK +2019 ; MidNumLet # Pf RIGHT SINGLE QUOTATION MARK +2024 ; MidNumLet # Po ONE DOT LEADER +FE52 ; MidNumLet # Po SMALL FULL STOP +FF07 ; MidNumLet # Po FULLWIDTH APOSTROPHE +FF0E ; MidNumLet # Po FULLWIDTH FULL STOP + +# Total code points: 7 + +# ================================================ + +0030..0039 ; Numeric # Nd [10] DIGIT ZERO..DIGIT NINE +0660..0669 ; Numeric # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE +066B ; Numeric # Po ARABIC DECIMAL SEPARATOR +06F0..06F9 ; Numeric # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE +07C0..07C9 ; Numeric # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE +0966..096F ; Numeric # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE +09E6..09EF ; Numeric # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE +0A66..0A6F ; Numeric # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE +0AE6..0AEF ; Numeric # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE +0B66..0B6F ; Numeric # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE +0BE6..0BEF ; Numeric # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE +0C66..0C6F ; Numeric # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE +0CE6..0CEF ; Numeric # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE +0D66..0D6F ; Numeric # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE +0DE6..0DEF ; Numeric # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE +0E50..0E59 ; Numeric # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE +0ED0..0ED9 ; Numeric # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE +0F20..0F29 ; Numeric # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE +1040..1049 ; Numeric # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE +1090..1099 ; Numeric # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE +17E0..17E9 ; Numeric # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE +1810..1819 ; Numeric # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE +1946..194F ; Numeric # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE +19D0..19D9 ; Numeric # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE +1A80..1A89 ; Numeric # Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE +1A90..1A99 ; Numeric # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE +1B50..1B59 ; Numeric # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE +1BB0..1BB9 ; Numeric # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE +1C40..1C49 ; Numeric # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE +1C50..1C59 ; Numeric # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE +A620..A629 ; Numeric # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE +A8D0..A8D9 ; Numeric # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE +A900..A909 ; Numeric # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE +A9D0..A9D9 ; Numeric # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE +A9F0..A9F9 ; Numeric # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE +AA50..AA59 ; Numeric # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE +ABF0..ABF9 ; Numeric # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE +FF10..FF19 ; Numeric # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE +104A0..104A9 ; Numeric # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE +10D30..10D39 ; Numeric # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +11066..1106F ; Numeric # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE +110F0..110F9 ; Numeric # Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE +11136..1113F ; Numeric # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE +111D0..111D9 ; Numeric # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE +112F0..112F9 ; Numeric # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE +11450..11459 ; Numeric # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE +114D0..114D9 ; Numeric # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE +11650..11659 ; Numeric # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE +116C0..116C9 ; Numeric # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +11730..11739 ; Numeric # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE +118E0..118E9 ; Numeric # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE +11950..11959 ; Numeric # Nd [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE +11C50..11C59 ; Numeric # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11D50..11D59 ; Numeric # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE +11DA0..11DA9 ; Numeric # Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE +16A60..16A69 ; Numeric # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE +16B50..16B59 ; Numeric # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE +1D7CE..1D7FF ; Numeric # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE +1E140..1E149 ; Numeric # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE +1E2F0..1E2F9 ; Numeric # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE +1E950..1E959 ; Numeric # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1FBF0..1FBF9 ; Numeric # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE + +# Total code points: 651 + +# ================================================ + +005F ; ExtendNumLet # Pc LOW LINE +202F ; ExtendNumLet # Zs NARROW NO-BREAK SPACE +203F..2040 ; ExtendNumLet # Pc [2] UNDERTIE..CHARACTER TIE +2054 ; ExtendNumLet # Pc INVERTED UNDERTIE +FE33..FE34 ; ExtendNumLet # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE +FE4D..FE4F ; ExtendNumLet # Pc [3] DASHED LOW LINE..WAVY LOW LINE +FF3F ; ExtendNumLet # Pc FULLWIDTH LOW LINE + +# Total code points: 11 + +# ================================================ + +200D ; ZWJ # Cf ZERO WIDTH JOINER + +# Total code points: 1 + +# ================================================ + +0020 ; WSegSpace # Zs SPACE +1680 ; WSegSpace # Zs OGHAM SPACE MARK +2000..2006 ; WSegSpace # Zs [7] EN QUAD..SIX-PER-EM SPACE +2008..200A ; WSegSpace # Zs [3] PUNCTUATION SPACE..HAIR SPACE +205F ; WSegSpace # Zs MEDIUM MATHEMATICAL SPACE +3000 ; WSegSpace # Zs IDEOGRAPHIC SPACE + +# Total code points: 14 + +# EOF diff --git a/third_party/web_unicode/pubspec.yaml b/third_party/web_unicode/pubspec.yaml new file mode 100644 index 0000000000000..8d9281ee95302 --- /dev/null +++ b/third_party/web_unicode/pubspec.yaml @@ -0,0 +1,10 @@ +name: web_unicode + +publish_to: none + +environment: + sdk: ">=2.12.0-0 <3.0.0" + +dev_dependencies: + args: any + path: any diff --git a/lib/web_ui/tool/unicode_sync_script.dart b/third_party/web_unicode/tool/unicode_sync_script.dart similarity index 73% rename from lib/web_ui/tool/unicode_sync_script.dart rename to third_party/web_unicode/tool/unicode_sync_script.dart index dbe4352704e3a..3f3573dd2cc3c 100644 --- a/lib/web_ui/tool/unicode_sync_script.dart +++ b/third_party/web_unicode/tool/unicode_sync_script.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// ignore_for_file: avoid_print + import 'dart:io'; import 'package:args/args.dart'; @@ -11,21 +13,10 @@ const int _kChar_A = 65; const int _kChar_a = 97; final ArgParser argParser = ArgParser() - ..addOption( - 'words', - abbr: 'w', - help: 'Sync the word break properties.', - ) - ..addOption( - 'lines', - abbr: 'l', - help: 'Sync the line break properties.', - ) ..addFlag( - 'dry', - abbr: 'd', - help: 'Dry mode does not write anything to disk. ' - 'The output is printed to the console.', + 'check', + help: 'Check mode does not write anything to disk. ' + 'It just checks if the generated files are still in sync or not.', ); /// A map of properties that could safely be normalized into other properties. @@ -76,33 +67,16 @@ class UnicodeRange { } } -final String codegenPath = path.join( - path.dirname(Platform.script.toFilePath()), - '../lib/src/engine/text', -); -final String wordBreakCodegen = - path.join(codegenPath, 'word_break_properties.dart'); -final String lineBreakCodegen = - path.join(codegenPath, 'line_break_properties.dart'); +final String webUnicodeRoot = path.dirname(path.dirname(Platform.script.toFilePath())); + +final String propertiesDir = path.join(webUnicodeRoot, 'properties'); +final String wordProperties = path.join(propertiesDir, 'WordBreakProperty.txt'); +final String lineProperties = path.join(propertiesDir, 'LineBreak.txt'); + +final String codegenDir = path.join(webUnicodeRoot, 'lib', 'codegen'); +final String wordBreakCodegen = path.join(codegenDir, 'word_break_properties.dart'); +final String lineBreakCodegen = path.join(codegenDir, 'line_break_properties.dart'); -/// Usage (from the root of the web_ui project). -/// -/// To generate code for word break properties: -/// ``` -/// dart tool/unicode_sync_script.dart -w -/// ``` -/// -/// To generate code for line break properties: -/// ``` -/// dart tool/unicode_sync_script.dart -l -/// ``` -/// -/// To do a dry run, add the `-d` flag: -/// -/// ``` -/// dart tool/unicode_sync_script.dart -d ... -/// ``` -/// /// This script parses the unicode word/line break properties(1) and generates Dart /// code(2) that can perform lookups in the unicode ranges to find what property /// a letter has. @@ -113,45 +87,21 @@ final String lineBreakCodegen = /// The line break properties file can be downloaded from: /// https://www.unicode.org/Public/13.0.0/ucd/LineBreak.txt /// -/// (2) The codegen'd Dart files is located at: -/// lib/src/engine/text/word_break_properties.dart -/// lib/src/engine/text/line_break_properties.dart +/// Both files need to be located at third_party/web_unicode/properties. +/// +/// (2) The codegen'd Dart files are located at: +/// third_party/web_unicode/lib/codegen/word_break_properties.dart +/// third_party/web_unicode/lib/codegen/line_break_properties.dart Future main(List arguments) async { final ArgResults result = argParser.parse(arguments); - final PropertiesSyncer syncer = getSyncer( - result['words'] as String?, - result['lines'] as String?, - result['dry'] as bool, - ); - - await syncer.perform(); -} - -PropertiesSyncer getSyncer( - String? wordBreakProperties, - String? lineBreakProperties, - bool dry, -) { - if (wordBreakProperties == null && lineBreakProperties == null) { - print( - 'Expecting either a word break properties file or a line break properties file. None was given.\n'); - print(argParser.usage); - exit(64); - } - if (wordBreakProperties != null && lineBreakProperties != null) { - print( - 'Expecting either a word break properties file or a line break properties file. Both were given.\n'); - print(argParser.usage); - exit(64); - } - if (wordBreakProperties != null) { - return dry - ? WordBreakPropertiesSyncer.dry(wordBreakProperties) - : WordBreakPropertiesSyncer(wordBreakProperties, wordBreakCodegen); - } else { - return dry - ? LineBreakPropertiesSyncer.dry(lineBreakProperties!) - : LineBreakPropertiesSyncer(lineBreakProperties!, lineBreakCodegen); + final bool isCheck = result['check'] as bool; + final List syncers = [ + WordBreakPropertiesSyncer(isCheck: isCheck), + LineBreakPropertiesSyncer(isCheck: isCheck), + ]; + + for (final PropertiesSyncer syncer in syncers) { + await syncer.perform(); } } @@ -161,14 +111,11 @@ PropertiesSyncer getSyncer( /// Subclasses implement the [template] method which receives as argument the /// list of data parsed by [processLines]. abstract class PropertiesSyncer { - PropertiesSyncer(this._src, this._dest) : _dryRun = false; - PropertiesSyncer.dry(this._src) - : _dest = null, - _dryRun = true; + PropertiesSyncer(this._src, this._dest, {required this.isCheck}); final String _src; - final String? _dest; - final bool _dryRun; + final String _dest; + final bool isCheck; String get prefix; String get enumDocLink; @@ -179,33 +126,36 @@ abstract class PropertiesSyncer { Future perform() async { final List lines = await File(_src).readAsLines(); - final List header = extractHeader(lines); final PropertyCollection data = PropertyCollection.fromLines(lines, defaultProperty); - final String output = template(header, data); + final String output = template(data); - if (_dryRun) { - print(output); + if (isCheck) { + // Read from destination and compare to the generated output. + final String existing = await File(_dest).readAsString(); + if (existing != output) { + final String relativeDest = path.relative(_dest, from: webUnicodeRoot); + print('ERROR: $relativeDest is out of sync.'); + print('Please run "dart tool/unicode_sync_script.dart" to update it.'); + exit(1); + } } else { - final IOSink sink = File(_dest!).openWrite(); + final IOSink sink = File(_dest).openWrite(); sink.write(output); } } - String template(List header, PropertyCollection data) { + String template(PropertyCollection data) { return ''' -// 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. +// Copyright 2022 Google LLC +// +// For terms of use, see https://www.unicode.org/copyright.html // AUTO-GENERATED FILE. // Generated by: tool/unicode_sync_script.dart -// -// Source: -// ${header.join('\n// ')} -import 'unicode_range.dart'; +// ignore_for_file: public_member_api_docs /// For an explanation of these enum values, see: /// @@ -214,17 +164,12 @@ enum ${prefix}CharProperty { ${_getEnumValues(data.enumCollection).join('\n ')} } -const String _packed${prefix}BreakProperties = +const String packed${prefix}BreakProperties = '${_packProperties(data)}'; +const int single${prefix}BreakRangesCount = ${_getSingleRangesCount(data)}; -UnicodePropertyLookup<${prefix}CharProperty> ${prefix.toLowerCase()}Lookup = - UnicodePropertyLookup<${prefix}CharProperty>.fromPackedData( - _packed${prefix}BreakProperties, - ${_getSingleRangesCount(data)}, - ${prefix}CharProperty.values, - ${prefix}CharProperty.$defaultProperty, -); +const ${prefix}CharProperty default${prefix}CharProperty = ${prefix}CharProperty.$defaultProperty; '''; } @@ -265,8 +210,8 @@ UnicodePropertyLookup<${prefix}CharProperty> ${prefix.toLowerCase()}Lookup = /// Syncs Unicode's word break properties. class WordBreakPropertiesSyncer extends PropertiesSyncer { - WordBreakPropertiesSyncer(super.src, String super.dest); - WordBreakPropertiesSyncer.dry(super.src) : super.dry(); + WordBreakPropertiesSyncer({required bool isCheck}) + : super(wordProperties, wordBreakCodegen, isCheck: isCheck); @override final String prefix = 'Word'; @@ -281,8 +226,8 @@ class WordBreakPropertiesSyncer extends PropertiesSyncer { /// Syncs Unicode's line break properties. class LineBreakPropertiesSyncer extends PropertiesSyncer { - LineBreakPropertiesSyncer(super.src, String super.dest); - LineBreakPropertiesSyncer.dry(super.src) : super.dry(); + LineBreakPropertiesSyncer({required bool isCheck}) + : super(lineProperties, lineBreakCodegen, isCheck: isCheck); @override final String prefix = 'Line'; @@ -477,19 +422,6 @@ void verifyNoOverlappingRanges(List data) { } } -List extractHeader(List lines) { - final List headerLines = []; - for (final String line in lines) { - if (line.trim() == '#' || line.trim().isEmpty) { - break; - } - if (line.isNotEmpty) { - headerLines.add(line); - } - } - return headerLines; -} - String removeCommentFromLine(String line) { final int poundIdx = line.indexOf('#'); return (poundIdx == -1) ? line : line.substring(0, poundIdx); diff --git a/tools/clang_tidy/lib/src/command.dart b/tools/clang_tidy/lib/src/command.dart index 278d6da154b9c..f2132b2666934 100644 --- a/tools/clang_tidy/lib/src/command.dart +++ b/tools/clang_tidy/lib/src/command.dart @@ -134,8 +134,7 @@ class Command { WorkerJob createLintJob(Options options) { final List args = [ filePath, - if (options.warningsAsErrors != null) - '--warnings-as-errors=${options.warningsAsErrors}', + '--warnings-as-errors=${options.warningsAsErrors ?? '*'}', if (options.checks != null) options.checks!, if (options.fix) ...[ diff --git a/tools/clang_tidy/test/clang_tidy_test.dart b/tools/clang_tidy/test/clang_tidy_test.dart index 73129a0f99665..13b2e08188ae1 100644 --- a/tools/clang_tidy/test/clang_tidy_test.dart +++ b/tools/clang_tidy/test/clang_tidy_test.dart @@ -379,19 +379,21 @@ Future main(List args) async { final WorkerJob jobNoFix = command.createLintJob(noFixOptions); expect(jobNoFix.command[0], endsWith('../../buildtools/mac-x64/clang/bin/clang-tidy')); expect(jobNoFix.command[1], endsWith(filePath.replaceAll('/', io.Platform.pathSeparator))); - expect(jobNoFix.command[2], '--'); - expect(jobNoFix.command[3], ''); - expect(jobNoFix.command[4], endsWith(filePath)); + expect(jobNoFix.command[2], '--warnings-as-errors=*'); + expect(jobNoFix.command[3], '--'); + expect(jobNoFix.command[4], ''); + expect(jobNoFix.command[5], endsWith(filePath)); final Options fixOptions = Options(buildCommandsPath: io.File('.'), fix: true); final WorkerJob jobWithFix = command.createLintJob(fixOptions); expect(jobWithFix.command[0], endsWith('../../buildtools/mac-x64/clang/bin/clang-tidy')); expect(jobWithFix.command[1], endsWith(filePath.replaceAll('/', io.Platform.pathSeparator))); - expect(jobWithFix.command[2], '--fix'); - expect(jobWithFix.command[3], '--format-style=file'); - expect(jobWithFix.command[4], '--'); - expect(jobWithFix.command[5], ''); - expect(jobWithFix.command[6], endsWith(filePath)); + expect(jobWithFix.command[2], '--warnings-as-errors=*'); + expect(jobWithFix.command[3], '--fix'); + expect(jobWithFix.command[4], '--format-style=file'); + expect(jobWithFix.command[5], '--'); + expect(jobWithFix.command[6], ''); + expect(jobWithFix.command[7], endsWith(filePath)); }); test('Command getLintAction flags third_party files', () async { diff --git a/tools/licenses/lib/main.dart b/tools/licenses/lib/main.dart index 54dfc0e000fdf..e9cea77d9eacc 100644 --- a/tools/licenses/lib/main.dart +++ b/tools/licenses/lib/main.dart @@ -2334,7 +2334,8 @@ class _RepositoryDartThirdPartyDirectory extends _RepositoryGenericThirdPartyDir @override bool shouldRecurse(fs.IoNode entry) { - return entry.name != 'devtools' // not linked in + return entry.name != 'binaryen' // not linked in + && entry.name != 'devtools' // test materials && entry.name != 'drt_resources' // test materials && entry.name != 'firefox_jsshell' // testing tool for dart2js && entry.name != 'd8' // testing tool for dart2js diff --git a/tools/licenses/lib/patterns.dart b/tools/licenses/lib/patterns.dart index 4797236bc1745..1d6bd79fc2920 100644 --- a/tools/licenses/lib/patterns.dart +++ b/tools/licenses/lib/patterns.dart @@ -1206,6 +1206,19 @@ final List csReferencesByUrl = [3], + checkLocalFirst: false, + pattern: RegExp( + kIndent + + r'\n// For terms of use, see (https://www.unicode.org/copyright.html)\n', + caseSensitive: false, + ) + ), ]; diff --git a/web_sdk/BUILD.gn b/web_sdk/BUILD.gn index 60a0b9dfee01b..a73a63361cee5 100644 --- a/web_sdk/BUILD.gn +++ b/web_sdk/BUILD.gn @@ -20,6 +20,15 @@ web_ui_sources = exec_script("//third_party/dart/tools/list_dart_files.py", ], "list lines") +web_engine_libraries = [ + ":skwasm_impl_library", + ":skwasm_stub_library", + ":web_engine_library", + ":web_ui_library", + ":web_ui_library_sources", + ":web_unicode_library", +] + group("web_sdk") { deps = [ ":flutter_ddc_modules", @@ -128,6 +137,13 @@ sdk_rewriter("skwasm_impl_library") { output_dir = "$root_out_dir/flutter_web_sdk/lib/_skwasm_impl/" } +sdk_rewriter("web_unicode_library") { + library_name = "web_unicode" + api_file = "//flutter/third_party/web_unicode/lib/web_unicode.dart" + input_dir = "//flutter/third_party/web_unicode/lib/web_unicode/" + output_dir = "$root_out_dir/flutter_web_sdk/lib/_web_unicode/" +} + copy("web_ui_library") { sources = [ "//flutter/web_sdk/libraries.json" ] @@ -147,13 +163,7 @@ template("_dartdevc") { if (flutter_prebuilt_dart_sdk) { action(target_name) { not_needed(invoker, [ "packages" ]) - deps = [ - ":skwasm_impl_library", - ":skwasm_stub_library", - ":web_engine_library", - ":web_ui_library", - ":web_ui_library_sources", - ] + deps = web_engine_libraries script = "//build/gn_run_binary.py" inputs = invoker.inputs @@ -177,17 +187,12 @@ template("_dartdevc") { prebuilt_dart_action(target_name) { forward_variables_from(invoker, "*") - deps = [ - ":skwasm_impl_library", - ":skwasm_stub_library", - ":web_engine_library", - ":web_ui_library", - ":web_ui_library_sources", - "//third_party/dart:create_sdk", - "//third_party/dart/pkg:pkg_files_stamp", - "//third_party/dart/utils/dartdevc:dartdevc_files_stamp", - "//third_party/dart/utils/dartdevc:dartdevc_sdk_patch_stamp", - ] + deps = web_engine_libraries + [ + "//third_party/dart:create_sdk", + "//third_party/dart/pkg:pkg_files_stamp", + "//third_party/dart/utils/dartdevc:dartdevc_files_stamp", + "//third_party/dart/utils/dartdevc:dartdevc_sdk_patch_stamp", + ] script = "//third_party/dart/pkg/dev_compiler/bin/dartdevc.dart" @@ -208,13 +213,7 @@ template("_dartdevc") { template("_kernel_worker") { if (flutter_prebuilt_dart_sdk) { action(target_name) { - deps = [ - ":skwasm_impl_library", - ":skwasm_stub_library", - ":web_engine_library", - ":web_ui_library", - ":web_ui_library_sources", - ] + deps = web_engine_libraries script = "//build/gn_run_binary.py" inputs = invoker.inputs @@ -239,17 +238,12 @@ template("_kernel_worker") { prebuilt_dart_action(target_name) { forward_variables_from(invoker, "*") - deps = [ - ":skwasm_impl_library", - ":skwasm_stub_library", - ":web_engine_library", - ":web_ui_library", - ":web_ui_library_sources", - "//third_party/dart:create_sdk", - "//third_party/dart/pkg:pkg_files_stamp", - "//third_party/dart/utils/dartdevc:dartdevc_files_stamp", - "//third_party/dart/utils/dartdevc:dartdevc_sdk_patch_stamp", - ] + deps = web_engine_libraries + [ + "//third_party/dart:create_sdk", + "//third_party/dart/pkg:pkg_files_stamp", + "//third_party/dart/utils/dartdevc:dartdevc_files_stamp", + "//third_party/dart/utils/dartdevc:dartdevc_sdk_patch_stamp", + ] script = "//third_party/dart/utils/bazel/kernel_worker.dart" @@ -306,6 +300,8 @@ template("_compile_platform") { "dart:_engine", "--source", "dart:_skwasm_stub", + "--source", + "dart:_web_unicode", ] if (flutter_prebuilt_dart_sdk) { args += [ @@ -477,6 +473,7 @@ template("_compile_ddc_modules") { "dart:ui", "dart:_engine", "dart:_skwasm_stub", + "dart:_web_unicode", "--no-summarize", "--packages", "file:///" + rebase_path(dart_sdk_package_config), @@ -579,15 +576,10 @@ if (!is_fuchsia) { output = "flutter-web-sdk-${full_platform_name}.zip" } deps = [ - ":flutter_ddc_modules", - ":flutter_legacy_platform_dills", - ":flutter_web_platforms", - ":skwasm_impl_library", - ":skwasm_stub_library", - ":web_engine_library", - ":web_ui_library", - ":web_ui_library_sources", - ] + ":flutter_ddc_modules", + ":flutter_legacy_platform_dills", + ":flutter_web_platforms", + ] + web_engine_libraries if (build_canvaskit) { deps += [ "//third_party/skia/modules/canvaskit" ] @@ -623,11 +615,10 @@ if (!is_fuchsia) { sources += get_target_outputs(":flutter_canvaskit_platform_dart2js_sound") sources += get_target_outputs(":flutter_canvaskit_platform_dart2js_unsound") - sources += get_target_outputs(":web_ui_library") - sources += get_target_outputs(":web_ui_library_sources") - sources += get_target_outputs(":skwasm_stub_library") - sources += get_target_outputs(":skwasm_impl_library") - sources += get_target_outputs(":web_engine_library") + foreach(web_engine_library, web_engine_libraries) { + sources += get_target_outputs(web_engine_library) + } + tmp_files = [] foreach(source, sources) { tmp_files += [ diff --git a/web_sdk/libraries.json b/web_sdk/libraries.json index 7f9c8789b2701..59a5062084d02 100644 --- a/web_sdk/libraries.json +++ b/web_sdk/libraries.json @@ -17,6 +17,9 @@ }, "_skwasm_stub": { "uri": "lib/_skwasm_stub/skwasm_stub.dart" + }, + "_web_unicode": { + "uri": "lib/_web_unicode/web_unicode.dart" } } }, @@ -36,6 +39,9 @@ }, "_skwasm_stub": { "uri": "lib/_skwasm_stub/skwasm_stub.dart" + }, + "_web_unicode": { + "uri": "lib/_web_unicode/web_unicode.dart" } } }, @@ -55,6 +61,9 @@ }, "_skwasm_impl": { "uri": "lib/_skwasm_impl/skwasm_impl.dart" + }, + "_web_unicode": { + "uri": "lib/_web_unicode/web_unicode.dart" } } } diff --git a/web_sdk/libraries.yaml b/web_sdk/libraries.yaml index 5a95df9ca4175..d16c7b11ae48e 100644 --- a/web_sdk/libraries.yaml +++ b/web_sdk/libraries.yaml @@ -27,6 +27,9 @@ dartdevc: _skwasm_stub: uri: "lib/_skwasm_stub/skwasm_stub.dart" + _web_unicode: + uri: "lib/_web_unicode/web_unicode.dart" + dart2js: include: - {path: "../dart-sdk/lib/libraries.json", target: dart2js} @@ -41,6 +44,9 @@ dart2js: _skwasm_stub: uri: "lib/_skwasm_stub/skwasm_stub.dart" + _web_unicode: + uri: "lib/_web_unicode/web_unicode.dart" + wasm: include: - {path: "../dart-sdk/lib/libraries.json", target: wasm} @@ -54,3 +60,6 @@ wasm: _skwasm_impl: uri: "lib/_skwasm_impl/skwasm_impl.dart" + + _web_unicode: + uri: "lib/_web_unicode/web_unicode.dart" diff --git a/web_sdk/sdk_rewriter.dart b/web_sdk/sdk_rewriter.dart index 617375e0eb9eb..84f51d80fc167 100644 --- a/web_sdk/sdk_rewriter.dart +++ b/web_sdk/sdk_rewriter.dart @@ -34,7 +34,7 @@ export 'dart:_engine' ), ]; -List generateApiFilePatterns(String libraryName, String extraImports) { +List generateApiFilePatterns(String libraryName, List extraImports) { return [ AllReplacer(RegExp('library\\s+$libraryName;'), ''' @JS() @@ -49,7 +49,7 @@ import 'dart:_js_annotations'; import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui; -$extraImports +${extraImports.join('\n')} ''' ), // Replace exports of engine files with "part" directives. @@ -84,6 +84,18 @@ final List stripMetaPatterns = [ AllReplacer('@visibleForTesting', ''), ]; +const Set rootLibraryNames = { + 'engine', + 'skwasm_stub', + 'skwasm_impl', +}; + +final Map extraImportsMap = { + RegExp('skwasm_(stub|impl)'): "import 'dart:_skwasm_stub' if (dart.library.ffi) 'dart:_skwasm_impl';", + 'engine': "import 'dart:_engine';", + 'web_unicode': "import 'dart:_web_unicode';", +}; + // Rewrites the "package"-style web ui library into a dart:ui implementation. // So far this only requires a replace of the library declarations. void main(List arguments) { @@ -94,6 +106,7 @@ void main(List arguments) { String Function(String source)? preprocessor; List replacementPatterns; String? libraryName; + if (results['ui'] as bool) { replacementPatterns = uiPatterns; } else { @@ -121,12 +134,8 @@ void main(List arguments) { final String inputFilePath = results['api-file'] as String; final String outputFilePath = path.join( directory.path, path.basename(inputFilePath)); - String extraImports = ''; - if (libraryName == 'engine') { - extraImports = "import 'dart:_skwasm_stub' if (dart.library.ffi) 'dart:_skwasm_impl';\n"; - } else if (libraryName == 'skwasm_stub' || libraryName == 'skwasm_impl') { - extraImports = "import 'dart:_engine';\n"; - } + + final List extraImports = getExtraImportsForLibrary(libraryName); replacementPatterns = generateApiFilePatterns(libraryName, extraImports); processFile( @@ -143,6 +152,22 @@ void main(List arguments) { } } +List getExtraImportsForLibrary(String libraryName) { + // Only our root libraries should have extra imports. + if (!rootLibraryNames.contains(libraryName)) { + return []; + } + + final List extraImports = []; + for (final MapEntry entry in extraImportsMap.entries) { + // A library shouldn't import itself. + if (entry.key.matchAsPrefix(libraryName) == null) { + extraImports.add(entry.value); + } + } + return extraImports; +} + void processFile(String inputFilePath, String outputFilePath, String Function(String source)? preprocessor, List replacementPatterns) { final File inputFile = File(inputFilePath); final File outputFile = File(outputFilePath) diff --git a/web_sdk/test/sdk_rewriter_test.dart b/web_sdk/test/sdk_rewriter_test.dart index 52cacc9e5306b..ffe6c40867f95 100644 --- a/web_sdk/test/sdk_rewriter_test.dart +++ b/web_sdk/test/sdk_rewriter_test.dart @@ -38,7 +38,6 @@ import 'dart:ui' as ui; import 'dart:extra'; - // Comment 2 part 'engine/file1.dart'; @@ -52,7 +51,7 @@ part 'engine/file3.dart'; '/path/to/lib/web_ui/lib/src/engine.dart', source, 'engine'), - generateApiFilePatterns('engine', "import 'dart:extra';\n"), + generateApiFilePatterns('engine', ["import 'dart:extra';"]), ); expect(result, expected); }); @@ -74,7 +73,7 @@ export 'engine/file3.dart'; '/path/to/lib/web_ui/lib/src/engine.dart', source, 'engine'), - generateApiFilePatterns('engine', ''), + generateApiFilePatterns('engine', []), ); } catch(error) { caught = error; @@ -125,4 +124,23 @@ void printSomething() { ); expect(result, expected); }); + + test('gets correct extra imports', () { + // Root libraries. + expect(getExtraImportsForLibrary('engine'), [ + "import 'dart:_skwasm_stub' if (dart.library.ffi) 'dart:_skwasm_impl';", + "import 'dart:_web_unicode';", + ]); + expect(getExtraImportsForLibrary('skwasm_stub'), [ + "import 'dart:_engine';", + "import 'dart:_web_unicode';", + ]); + expect(getExtraImportsForLibrary('skwasm_impl'), [ + "import 'dart:_engine';", + "import 'dart:_web_unicode';", + ]); + + // Other libraries (should not have extra imports). + expect(getExtraImportsForLibrary('web_unicode'), isEmpty); + }); }